I'm using the React hook useReducer to handle complex, multi-layer form data in state.
I have followed the direction from this tutorial: https://levelup.gitconnected.com/handling-complex-form-state-using-react-hooks-76ee7bc937.
In the tutorial, the checkbox state is set at the top level of the state object. However, My checkbox is below the top layer (layer 3 to be exact). The problem is that my checkbox component will change it's state value, but will place itself at the top level and not where it's supposed to be at level 3.
Tutorial's State
isMember is at the top level
const initialState = {
firstName: "",
lastName: "",
address: {
addressLine1: "",
addressLine2: "",
pinCode: ""
},
isMember: false
};
My State
enabled is below the top level
const initState =
{
radio:{
tx: {
name:'',
enabled:'',//THIS IS WHERE THE STATE SHOULD CHANGE.
parameters:{
frequency:'',
bandwidth:'',
},
},
}
//BUT THIS IS WHERE IT IS GETTING SET.
};
Below is my implementation of the updateForm function:
const updateForm = React.useCallback(({ target: { value, name, type } }) => {
const updatePath = name.split(".");
console.log("updateForm | updatePath: ", updatePath);
// Set top-level key-pairs.
// Just need specific component & value to update.
if (updatePath.length === 1) {
const [id] = updatePath;
dispatch({
type: "TF",
[id]: value
});
}
// Set key-pairs that're below top-level.
// Need "path" to component ('name') & value to update.
// More condensed solution, rather than multiple if(length === 3,4,...).
if (updatePath.length >= 2) {
// Set checkboxes.
if (type === "checkbox") {
let elem = updatePath[updatePath.length - 1];
dispatch(prevState => ({
[name]: !prevState[name]
}));
return;
}
dispatch({
_path: updatePath,
_value: value
});
}
}, []);
I have tried many different approaches to the dispatch function and the reducer function. I have also tried understanding the relationship between the dispatch and reducer functions, but I haven't found anything that helps me understand what's happening when the reducer's action parameter is of type function.
I could really use your help understanding what's going on with the checkbox dispatch/reducer function relationship in the tutorial. From what I've researched, this is the only implementation that uses the reducer's action parameter's constructor type to make decisions (using constructor === Function & constructor === Object). From what I understand, typically a switch() statement is used instead, and that's all I've been able to find online.
I could also use your help understanding how to get my checkbox to correctly change its value in state. Basically, how do I change the state of this component that is below the top layer?
After continuing to try out more ideas, I came to a solution I can live with. Hopefully this solution will help anyone who experiences the same problem.
I changed the checkbox section in my updateForm() as follows:
updateForm()
// Set checkboxes.
if (type === "checkbox"){
dispatch({
_path: updatePath,
_value: checked,
_type: type
});
return;
}
In the reducer() method I completely avoid checking for constructor of type Function, and implement checkbox data handling as follows:
reducer()
if(has(updateArg, "_path") && has(updateArg, "_value") && has(updateArg, "_type")){
const { _path, _value, _type } = updateArg;
if(_type === "checkbox"){
return produce(state, draft => {
set(draft, _path, _value)
})
}
}
I don't especially like this solution due reliance on the checkbox's checked element property. The tutorial's implementation of using the prevState argument would be my preference, but obviously I wasn't able to get it to work in my circumstance.
If anyone comes up with a better solution I will mark that as the answer. I would appreciate any thoughts and opinions as well.