Redux form initial values with Map() - javascript

i have a redux form and i want to set the initial values property to a Map and not an object. This is mandatory and i cannot change this :P
Therefore i set an initialValues Map like this:
export const initialValuesForm = (timeSlots, formValues) => {
const initialValues = Map();
const date = formValues[DATE_PICKER_FORM_FIELD] && formValues[DATE_PICKER_FORM_FIELD].startDate;
const travelers = formValues[TRAVELERS_FORM];
initialValues[POPUP_DATE_PICKER] = date;
initialValues[TRAVELERS_FORM_SELECT] = travelers;
return initialValues;
};
The formValues is an object with the values of another form from the state.
The very weird situation is that when i open the pop up with the form the values object and initial object are an empty object. When i change a value all the values are updated and are inside the Map. My mapStatetoProps function is this:
const mapStateToProps = (state) => {
return {
availability,
locale,
activityToBeAdded,
popUpFormErrors,
initialValues: initialValuesForm(timeSlots, searchFormValues)
};
};
Why is this happening? Any ideas?

Related

Is there a way to dynamicaly create state with useState in React

I am building a react app that has input fields that should be stored to the state.
I can easily store these values using the useState hook. The challenge I am facing however is that I do not know the fields as I pull them from a database and they can change. Is there a way that I can set up the useState to be created dynamically so they can be added or removed based on what is in the database. eg.
The fields would be pulled from a database and stored into an array like so:
const fields = [userName, userAge, userLocation, userOccupation];
The useState would be
const[username, setUserName] = useState('');
const[userAge, setUserAge] = useState('');
...
If I added another item to the array, it should automatically create state for that item.
What would be the best way to achieve this?
Thanks.
One way to dynamically create state variables based on the fields array is to use the useReducer hook in combination with a reducer function.
For example;
import { useReducer } from 'react';
const fields = [userName, userAge, userLocation, userOccupation];
const initialState = {};
fields.forEach(field => {
initialState[field] = '';
});
const reducer = (state, action) => {
switch (action.type) {
case 'SET_FIELD_VALUE':
return {
...state,
[action.field]: action.value
};
default:
return state;
}
};
const [state, dispatch] = useReducer(reducer, initialState);
// You can then use dispatch to update the state for a specific field
dispatch({ type: 'SET_FIELD_VALUE', field: 'userName', value: 'John' });
This way, you can dynamically create state variables for each field in the fields array, and use the dispatch function to update the state for a specific field.

How can I handle change in multiple input field and send the data to an api with axios?

I'm trying to handle change in multiple input text field and send the value to an API
Here is what i have tried
const [state, setState] = useState({
Value_A:'',
Value_B:'',
Value_c:'',
Value_D:'',
Value_e:''})
The handleChange function right here
function handleChange(evt) {
const value = evt.target.value;
setState({
...state,
[evt.target.name]:value
})
}
So how can I do to get those values inside the function handleSubmit()
const handleSubmit = (e) => {
const a = {
// How to get those values here?
Thank you!
The concept you are trying here is known as Controlled Component in reactjs, on every change of input we update the associated state and on form submit we get the updated state. In your case you will get it like:
const handleSubmit = (e) => {
e.preventDefault();
let formValues = {...state}; // spread operator is used to clone the data
// Your API call goes here
}
Controlled Component Reference
Try this.
const handleSubmit = (e) => {
const a = {...state};
// Your API call goes here
}

Why isn't my React Hook updating when I setState?

I'm using react useState, where the state is an object with some nested properties. When I call setState on it, I'm not seeing a re-render or the state being updated. I assume react is seeing that the new state equals the old state and so no updates occur. So, I've tried cloning the state first, but still am not seeing any updates.
How can I get this function to cause the state to update?
export type TermEditorStateRecord = {
term: SolrTermType;
state: SolrTermEditorRecordState;
classifications: { [key: string]: string };
};
export type TermEditorStateRecordMap = {
[phrase: string]: TermEditorStateRecord;
};
const [records, setRecords] = useState({});
const setRecordClassification = (label, key, value) => {
const cloned = new Object(records) as TermEditorStateRecordMap;
cloned[label].classifications[key] = value;
setRecords(cloned);
};
I apologize for the TypeScript types, but I've included them here so that you can see the expected shape of the state.
Is it not updating because the changes are deeply nested? Is there a way to get this to work, or do I need to somehow pull the state that changes out into its own state?
new Object does not make a deep copy, so for setRecords it's the same instance and it won't trigger the re-render,
const obj = {
a: {
b: "b"
}
};
const copy = new Object(obj);
copy["c"] = "c";
console.log(obj);
You'll need to manually updated the nested property :
const setRecordClassification = (label, key, value) => {
setRecords(record => ({
...record,
[label]: {
...record[label],
classifications: {
...record[label].classifications,
[key]: value
}
}
}));
};
or to create a copy, use :
const cloned = JSON.parse(JSON.stringify(record));
cloned[label].classifications[key] = value;
setRecords(cloned);

cant update context state when using hooks with a complex object to set providers value

When I call toggleFilterSidebar it should toggle the state of filterSidebarIsOpen from false to true and vice versa but onClick nothing happens, but when I pass the Provider value directly as an object it works.
Why does this work?
1).
return <FilterSidebarContext.Provider value={{
toggleFilterSidebar,
filterSidebarIsOpen,
filters,
}}>{children}</FilterSidebarContext.Provider>;
and this doesnt
2).
const [value] = useState({
toggleFilterSidebar,
filterSidebarIsOpen,
filters,
});
return <FilterSidebarContext.Provider value={value}>{children}</FilterSidebarContext.Provider>;
My Code
FilterSidebar.context.js
import React, { useState } from 'react';
export const FilterSidebarContext = React.createContext({});
export const FilterSidebarProvider = ({ children }) => {
const [filterSidebarIsOpen, setFilterSidebarIsOpen] = useState(true);
const toggleFilterSidebar = () => setFilterSidebarIsOpen(!filterSidebarIsOpen);
const [filters] = useState({ regions: [] });
const [value] = useState({
toggleFilterSidebar,
filterSidebarIsOpen,
filters,
});
return <FilterSidebarContext.Provider value={value}>{children}</FilterSidebarContext.Provider>;
};
export const FilterSidebarConsumer = FilterSidebarContext.Consumer;
export default FilterSidebarContext;
FilterButton.js
const FilterButton = ({ className, getTotalActiveFilters }) => {
const { toggleFilterSidebar, filterSidebarIsOpen } = useContext(FilterSidebarContext);
return <Button className={cx({ [active]: filterSidebarIsOpen })} onClick={toggleFilterSidebar} />;
};
With this code:
const [value] = useState({
toggleFilterSidebar,
filterSidebarIsOpen,
filters,
});
you are providing useState with an initial value which is only used when the component is first mounted. It will not be possible for value to ever change since you aren't even creating a variable for the setter (e.g. const [value, setValue] = useState(...)).
I assume you are using useState here to try to avoid a new object being created with each render and thus forcing a re-render of everything dependent on the context even if it didn't change. The appropriate hook to use for this purpose is useMemo:
const value = useMemo(()=>({
toggleFilterSidebar,
filterSidebarIsOpen,
filters
})[filterSidebarIsOpen]);
I've only put filterSidebarIsOpen into the dependencies array, because with your current code it is the only one of the three that can change (toggleFilterSidebar is a state setter which won't change, filters doesn't currently have a setter so it can't change).
useState expects a function to set the value after useState initially does, so if value represents state, setValue would represent setState...
const [value, setValue] = useState(initialValue);
then use setValue to change it
onClick={() => setValue(newValue)}

Pass string value as object to Redux component with PropTypes in React

A component using Redux example from React Final Form was created in index.js.
<FormStateFromRedux valueName="valueString" form="counter" />
It is using redux to track values, using prop-types it should receive object name to return exact object value:
const FormStateFromRedux = ({ state, valueName }) => (
<p>{state.values.valueName}</p>
)
export default connect((state, ownProps) => ({
state: getFormState(state, ownProps.form)
}))(FormStateFromRedux)
FormStateFromRedux.propTypes = {
valueName: PropTypes.objectOf(PropTypes.string)
};
It is possible to return value when object path is set manually, here I want to make reusable component to return values using PropTypes but don't know what kind of type to choose. Is it possible to pass value as string? May someone know what should be correct approach in this case?
UPDATE
It is possible to get string value inside object using []
const FormStateFromRedux = ({ state, valueName }) => (
<p>{state.values[valueName]}</p>
)
You should avoid passing whole form state to component. Component should have only necessary props.
const FormStateFromRedux = ({ valueName }) => ( <p>{valueName}</p> );
export default connect((state, props) => {
const formState = getFormState(state, props.form);
const { value : { valueName } } = formState;
return { valueName };
})(FormStateFromRedux);
FormStateFromRedux.propTypes = {
valueName: PropTypes.string
};

Categories