React uses hook — the pit of usestate

Time:2022-1-8

Recently, the project used umi3 + react17 + antd pro5

Pit of usestate encountered in project

1. Usestate is not suitable for the change of complex objects

Because usestate cannot be merged and updated like setstate, when using the second parameter of usestate to update data, a complete structure must be passed in, not just the changed part.

2. Usestate asynchronous callback problem

When usestate is used to update data, the latest data cannot be obtained immediately.

const [name, setName] = useState('dx');
const handleTest = () => {
  console.log(name) // dx
  setName('dx1')
  console.log(name) // dx
}

Solution

1、 Use with useeffect

const [name, setName] = useState('dx');
const handleTest = () => {
  console.log(name) //dx
  setName('dx1')
  console.log(name)//dx
}
  
useEffect(() => {
  console.log(name) //dx1
},[name])

2、 Create a new variable to save the latest data

const [name, setName] = useState('dx');
const handleTest = () => {
  console.log(name) //dx
  const newName = "dx1"
  setName(newName)
  console.log(newName) //dx1
}

3. According to the rules of hook, there are restrictions on the location of usestate

  • Only the top level calls Hook: useState () cannot be called in loops, conditions, nested functions, etc.
  • In multiple usestate() calls, the order of calls must be the same between renderings.
  • Call hook only from react function: usestate() must be called only inside a function component or custom hook.

4. Use usestate to change data in the form of callback function

const [a, setA] = useState({c:1})
/**Olda is the previous a and return is the new value set*/
setA((oldA) => {
  return {c: oldA.c + 1}
})

5. The value stored in usestate is only the reference (reference type) of the value

const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj )
const [useState2, setUseState2] = useState(textObj )
/**The usestate operation should not be placed in the outermost layer of the function. Here is a simple code display. You can put the set operation in a function*/
setUseState1((oldUseState1) => {
  oldUseState1.age = 18
  return {...oldUseState1}
})
useEffect(() => {
  /**Changing one will lead to the problem of changing both, deep and shallow copies*/
  console.log(useState1)  // {name: "dx", age: 18}
  console.log(useState2)  // {name: "dx", age: 18}
},[useState1])

Solutions

const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj )
const [useState2, setUseState2] = useState(JSON.parse(JSON.stringify(textObj)))
/**The usestate operation should not be placed in the outermost layer of the function. Here is a simple code display. You can put the set operation in a function*/
setUseState1((oldUseState1) => {
  oldUseState1.age = 18
  return {...oldUseState1}
})

useEffect(() => {
  /**Changing one will lead to the problem of changing both, deep and shallow copies*/
  console.log(useState1)  // {name: "dx", age: 18}
  console.log(useState2)  // {name: "dx"}
},[useState1])

6. Usestate, if the reference data is saved, the useeffect cannot detect the change?

const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj)
/**The usestate operation should not be placed in the outermost layer of the function. Here is a simple code display. You can put the set operation in a function*/
setUseState1((oldUseState1) => {
  oldUseState1.age = 18
  return oldUseState1
}
useEffect(() => {
  console.log(useState1)  
},[useState1])
//The result was no response

resolvent

const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj)
/**The usestate operation should not be placed in the outermost layer of the function. Here is a simple code display. You can put the set operation in a function*/
setUseState1((oldUseState1) => {
  oldUseState1.age = 18
  /**Only when a new object is returned can useeffectc detect it*/
  return {...oldUseState1}
}
useEffect(() => {
  console.log(useState1)  // {name: "dx", age: 18}
},[useState1])

7. Usestate cannot save a function

Do you try to save the function reference as a variable in usestate?
For example:

const testFunciton1 = () => {
  console.log({name: 'dx',age: '18'})
}
/**Usestate save function test*/
const [stateFunction, setstateFunction] = useState<() => void>(testFunciton1);
useEffect(() => {
 console.log(stateFunction)// {name: 'dx', age: 18}
}, [stateFunction])

Testfunciton1 was never called in the code, but testfunciton1 was executed
Useeffect prints an undefined.

Change the code a little and test it again

const testFunciton1 = () => {
  console.log({name: 'dx',age: '18'})
  return {
    name: 'yx',
    age: '17'
  }
}
/**Usestate save function test*/
const [stateFunction, setstateFunction] = useState<() => void>(testFunciton1);
useEffect(() => {
 console.log(stateFunction)// {name: 'dx', age: 18} // {name: 'yx', age: 17}
}, [stateFunction])

Obviously, in usestate, the function is called automatically and the value returned by the function is saved, not the function itself.

Solutions
If the function cannot be saved using usestate, you can use the hook usecallback.

/**Usecallback, the use parameter is consistent with useeffect*/
const testFunction = useCallback(() => {
  //The function returned by usecallback is built in usecallbak
  const testFunciton1 = () => {
    console.log({ name: 'dx', age: '18' });
    return {
      name: 'yx',
      age: '17',
    };
  };
  return testFunciton1;
}, []);
useEffect(() => {
  console. log(testFunction());//  Printing is a function
}, [testFunction]);

Recommended Today

Proper memory alignment in go language

problem type Part1 struct { a bool b int32 c int8 d int64 e byte } Before we start, I want you to calculatePart1What is the total occupancy size? func main() { fmt.Printf(“bool size: %d\n”, unsafe.Sizeof(bool(true))) fmt.Printf(“int32 size: %d\n”, unsafe.Sizeof(int32(0))) fmt.Printf(“int8 size: %d\n”, unsafe.Sizeof(int8(0))) fmt.Printf(“int64 size: %d\n”, unsafe.Sizeof(int64(0))) fmt.Printf(“byte size: %d\n”, unsafe.Sizeof(byte(0))) fmt.Printf(“string size: %d\n”, […]