Trying to catch up on the React Hooks. I'm reading that they recommend the use of the Hook useReducer
when dealing with a complex state
. But my doubt starts from the following scheme:
Using React + Typescript, suppose I have a state with several fields (I'll give an example with classes):
type Person = {
username: string,
email: string
}
type Pet = {
name: string,
age: number
}
this.state: MyState = {
person: Person,
pet: Pet,
loading: boolean
}
If I wanted to handle this state with a new Hooks-based approach, I could think of several options:
Option 1: using a Hook useState
for each field
const [person, setPerson] = useState<Person>(null)
const [pet, setPet] = useState<Pet>(null)
const [loading, setLoading] = useState<boolean>(false)
This method has the disadvantage of low scalability and some of my real states have at least 15 fields, is unmanageable.
Option 2: Using a single setState
for the entire object
const [state, setState] = useState<MyState>({
person: null,
pet: null,
loading: false
})
This is the method that seems simplest to me, where I can simply do setState((prev) => {...prev, person: {username: 'New', email: '[email protected]'}})
or adapt it to any field modification. I can even update several fields at once.
Option 3: use a useReducer
for each of the complex fields by passing a specific reducer for each one, use useState
for the simple ones
const [person, dispatchPerson] = useReducer<Person>(personReducer)
const [pet, dispatchPet] = useReducer<Pet>(petReducer)
const [loading, setLoading] = useState<boolean>(false)
I find this one manageable, but I don't see the point of having to set up a reduce function with a multi-line switch, in addition to the tedious process of setting the dispatching types in Typescript for each reduce function when you could just use setState and be done with it.
Option 4: use one useReducer
for the entire state
const [state, dispatch] = useReducer(generalReducer)
The main problem with this is the type of the reducer, think of 15 fields, where all the types and the structure of the information to update them are different. Specifying the types in Typescript does not scale or is unclear. There are several articles about this and none of them solve the problem in a clean way (example 1), or they are extremely simple and don't apply to the problem (example 2).
What would be the best way to handle this type of cases? Where the number of fields in the state is large and can have several levels of depth. Are there good practices or any official examples that represent these cases? The examples with a number field to handle a simple counter that bloggers or official documentation people like so much are not being very helpful.
Any light on the subject would be more than welcome! Thanks in advance and sorry about my English
get
/set
from anywhere in your App, the Redux strategy seems reasonable to me, your Option 4, with optional use of Option 3. The App has one large state tree with one reducer. You can break up responsibility into sub-reducers which are ultimately combined usingcombineReducers
to create the overarching reducer. For local component state, Option 1&2 make sense to me. I tend to use Option 1. I agree with everything you've said. I haven't seen any new, innovative ways to useuseReducer
. – ZanezaneskiuseMethods
reducer and thought of you. It's an interesting way to scaffold things. – Zanezaneski