current position:Home>Small problems encountered by react usereducer and Solutions

Small problems encountered by react usereducer and Solutions

2022-04-29 08:10:56A programmer who can only write bugs

stay useReducer Of reducer in , Yes state To operate , It will lead to mistakes

function getAnalyzeItem(){
    
    return {
    
        a: 1,
        b: 2
    }
}
//  Wrong writing  
function analyzeReducer(state: TFilterItemVal[], action: TReducerAction<TFilterItemVal>) {
    
    const {
     index, data, type } = action;
    switch (type) {
    
        case "add":
            state.push(getAnalyzeItem());
            return [...state];
        case "delete":
            typeof index === "number" &&state.splice(index, 1);
            return[...state];
        case "update":
            if (typeof index === "number") {
    
                state[index] = {
    
                    ...state[index],
                    ...data,
                }
                return [...state];
            }
        case "init":
            return [getAnalyzeItem()];
        default:
            return state;
    }
}
const [analyzeLats, analyzeDispatch] = useReducer(analyzeReducer, [getAnalyzeItem()]);
//  Write it correctly  
function analyzeReducer(state: TFilterItemVal[], action: TReducerAction<TFilterItemVal>) {
    
    const {
     index, data, type } = action;
    /// The point is //
    let oldState = [...state];
    /
    switch (type) {
    
        case "add":
            oldState.push(getAnalyzeItem());
            return oldState;
        case "delete":
            typeof index === "number" && oldState.splice(index, 1);
            return oldState;
        case "update":
            if (typeof index === "number") {
    
               oldState[index] = {
    
                    ...oldState[index],
                    ...data,
                };
                return oldState;
            }
        case "init":
            return [getAnalyzeItem()];
        default:
            return state;
    }
}
const [analyzeLats, analyzeDispatch] = useReducer(analyzeReducer, [getAnalyzeItem()]);

This place must pay attention to ,state It's a immutable Of , That is, constant , If state It's an object , Make a copy that deep , It is being modified , If you modify it directly , Then there will be mistakes .

Like the code above ,state It was originally an object , I use... Directly push and splice After the operation , You will find that he will add one later , Add two later , That is, sometimes normal , Sometimes abnormal . Thought about it on the way , It may be this idea reducer In the middle of state, On the first execution , It will be set to the status value by default , Because it's an object , So it will open up a space in memory #fff Storage , After that, if you modify it directly state So it's like modifying the original value , So in the follow-up operation, we will take out the last state As a basis , Continue to modify . for instance The page is still loading Data time , That is to say updateQueue When it's not empty , I went to Directly modifying state, It will show , When the page is stable , After rendering , Then directly modify state, Two will be added or deleted . Why does this happen , My guess is as follows :
1. Because of the modification setState stay react Inside is through queue To unify , So it will lead to many times setState Perform post consolidation processing , So when the rendering is not over , I just modified state, Then it may be twice dispatch( according to redux Understanding in , He was in useReducer It will also be executed once dispatch, It's just a message type It's a fixed value , Will default to default in ), There's another one in the back dispatch({type: “add”}), This will be merged with the initialized , The default is not returned state, It's a modified state, That's two getAnalyzeItem()
2. When he finished rendering ,state It has been confirmed that , If called again dispatch({type: “add”}), Yes state Conduct push A new value , Will first modify its original value , after , It will enter updateQueue Waiting for execution , When it comes to execution , Will take out the old state( It has been modified at this time ), Do it again push, And return to a new state, Then start rendering . This leads to the point of adding , But added two questions .

resolvent :
1. Use immer To manipulate objects ( It's actually very much like deconstruction , Copy an object separately , Then look down layer by layer , Find the corresponding element , A deep copy , And then modify it , Form new objects . In the new object , Except for the modified element , The other elements are the same as the previous elements )

let obj = {
    
	a: {
     aa: {
     aaa: 1 }, ab: {
     aba: 2 } },
	b: {
     bb: 2 },
	c: {
     cc: {
     ccc: {
     cccc: 3 } } },
};
let newObj = produce(obj, (prevState) => {
    
	prevState.a.aa.aaa = 2;
});
console.log(obj.a.ab === newObj.a.ab);	// true
console.log(obj.a, newObj.a);			// false  Because one of its child elements has been modified 
console.log(obj.b === newObj.b, newObj.c === obj.c);	// true true
2.  Deconstruct ( If the level is deep , Need a layer by layer structure , It's like peeling onions , May peel tears )
3.  Write a deep copy yourself ( It creates a whole new object , Every node   Dissimilarity , High performance consumption , Recommend index **)

copyright notice
author[A programmer who can only write bugs],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2022/119/202204290558476256.html

Random recommended