Adding-States-to-Components

useStateuseReducer的使用决策

useStateuseRuducer都允许开发者向组件添加状态以进行更新。

// useRuducer
const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}
复制成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

ISSUE: react hook状态更新: 随着业务变化导致新的state增加,而且几个state还是同一时机进行更新(互不独立),此时需要使用useReducer

EXAMPLES

  1. 由于闭包问题这段错误代码得到了过时的state

    React.useEffect(() => {
      const id = setInterval(() => {
        setCount(count + 1)
      }, 1000)
      return () => clearInterval(id)
    }, [count])
    
    复制成功
    1
    2
    3
    4
    5
    6
  2. 此时useEffect的依赖项数组只有count,可以考虑setCount传递一个函数或者使用useRef.current暂存解决。

    React.useEffect(() => {
      const id = setInterval(() => {
        setCount((count) => count + 1)
      })
      return () => clearInterval(id)
    }, [count])
    
    复制成功
    1
    2
    3
    4
    5
    6
  3. 噢业务变化,多个state都需要参与进来这个副作用了,需要运用useRuducer

    • 目的是减少依赖项数组,此时不需要在副作用里访问state,这个state会在特定action中去改变
    • action.type === 'increment' 中,count = count + step
React.useEffect(() => {
  const id = setInterval(() => {
    dispatch({ type: 'increment' })
  })
  return () => clearInterval(id)
}, [])
复制成功
1
2
3
4
5
6

PS: 如果不用dispatch而是在副作用里面访问多个state,就会写出无法正常运作的代码:

  • 虽然deps数组添加step,setCount也是用的函数,
  • 但是,每次step更新,会清除interval,然后添加新的setInterval
  • 符合预期的代码需要保证使用一个计时器。
//WRONG
React.useEffect(() => {
  const id = setInterval(() => {
    setCount((count) => count + step)
  })
  return () => clearInterval(id)
}, [step])
复制成功
1
2
3
4
5
6
7

最后

  1. 截图:以前看到的form表单的reducer。此处还使用了:

    • JS的动态属性名。

    • JS的对象解构。

image-20220426124233758
  1. useStateuseReducer的使用决策:
image-20220426102110311
晓露寝安浅云逍遥十漾轻拟