实现useReducer

大家好,我是万维读客的讲师曹欢欢。上节课我们增加了useState功能,这节我们在此基础之上,增加一个useReducer的功能,作为useState的包装能力。

useReducer介绍

useReducer 是一个 React Hook,它允许你向组件里面添加一个用于管理状态的 reducer, 类似简化版的redux。具体可以参考官方useReducer文档:https://zh-hans.react.dev/reference/react/useReducer,下面给个例子:

function reducer(state, action){
      switch(action.type){
        case 'add': return state + 1;
        case 'sub': return state - 1;
        default: return state;
      }
}
function App() {
  const [count, dispatch] = Treact.useReducer(reducer, 10);
  const handleClick = (type) => {
    dispatch({type})
  }
  return (<div>
      <div>{count}</div>
      <span onClick={()=>handleClick('add')}>+</span>
      <span onClick={()=>handleClick('sub')}>-</span>
    </div>
  );
}

编写测试用例

我们在上一节的基础上,增加测试用例如下:

describe('fiber useReducer test', () => {
  it('render useReducer', async () => {
    const globalObj = {};

    function reducer(state, action){
      switch(action.type){
        case 'add': return state + 1;
        case 'sub': return state - 1;
        default: return state;
      }
    }
    function App() {
      const [count, dispatch] = Treact.useReducer(reducer, 10);
      globalObj.count = count;
      globalObj.dispatch = dispatch;
      return (
        <div>{count}</div>
      );
    }
    const container = document.createElement('div');
    const root = Treact.createRoot(container);
    await Treact.act(() => {
      root.render(<App />);
      expect(container.innerHTML).toBe('');
    });
    await Treact.act(() => {
      globalObj.dispatch({type: 'add'});
    });
    console.log('globalObj.count', globalObj.count);
    expect(globalObj.count).toBe(11);
    await Treact.act(() => {
      globalObj.dispatch({type: 'sub'});
    });
    console.log('globalObj.count', globalObj.count);
    expect(globalObj.count).toBe(10);
  });
})

然后我们看控制台提示测试用例报错,找不到useReducer方法,下面我们就来补全这个方法。

实现useReducer

我们增加useReducer函数,基于我们上一节实现的useState,其实这里就比较简单了。代码如下:

export function useReducer(reduce, initialState) {
    const [state, setState] = useState(initialState);
    const dispatch = (action) => {
        setState(state => reduce(state, action))
    }
    return [state, dispatch]
}

检查控制台测试用例执行通过,代码功能完成。

stdout | treact05/jsx.test.jsx > fiber useReducer test > render useReducer
globalObj.count 11

stdout | treact05/jsx.test.jsx > fiber useReducer test > render useReducer
globalObj.count 10

 ✓ treact05/jsx.test.jsx (3)
   ✓ async render Function Component (1)
     ✓ render with act
   ✓ fiber useState test (1)
     ✓ render useState
   ✓ fiber useReducer test (1)
     ✓ render useReducer

 Test Files  1 passed (1)
      Tests  3 passed (3)
   Start at  14:25:25
   Duration  40ms


参考

  1. useState文档:https://zh-hans.react.dev/reference/react/useState


请遵守《互联网环境法规》文明发言,欢迎讨论问题
扫码反馈

扫一扫,反馈当前页面

咨询反馈
扫码关注
返回顶部