useReducer源码实现

要知道useReducer是useState的语法糖

function useState (initial){

  return  useReducer(null,initial)

}

function useReducer(reducer,initialState){
  hookStates[hookIndex] = hookStates[hookIndex]||initialState;
  let currentIndex = hookIndex;
  function dispatch(action){
    hookStates[currentIndex] = reducer?reducer(hookStates[currentIndex],action):action;
    console.log(hookStates[currentIndex])
    render();
  }
  return [hookStates[hookIndex++],dispatch];
}

看组件里具体写了什么

function Counter1(){
  let [number,setNumber] = useState(0);
  return (
    <div>
      <p>{number}</p>
      <button onClick={()=>setNumber(number+1)}>+</button>
    </div>
  )
}
function Counter2(){
  //reducer 初始状态
  let [state,dispatch] = useReducer(counterReducer,0);
  return (
    <div>
      <p>{state}</p>
      <button onClick={()=>dispatch({type:'add'})}>+</button>
    </div>
  )
}
function render(){
  hookIndex=0;
  ReactDOM.render(
    <div><Counter1/><hr/><Counter2/></div>,
    document.getElementById('root')
  );
}
render();
useState这里不用说,因为useReducer会了,useState也就会了
我们在Counter2组件中点击+,会触发useReducer函数里面的dispatch方法,这里的dispatch方法里面有action   
 

如果用useReducer那么一定是两个参数啊,第一个参数是传统redux中的reducer函数,看代码

function useReducer(reducer,initialState){
  hookStates[hookIndex] = hookStates[hookIndex]||initialState;
  let currentIndex = hookIndex;
  function dispatch(action){
    hookStates[currentIndex] = reducer?reducer(hookStates[currentIndex],action):action;
    console.log(hookStates[currentIndex])
    render();
  }
  return [hookStates[hookIndex++],dispatch];
}
function useState(initialState){
  return useReducer(null,initialState);
}
function counterReducer(state,action){
   switch(action.type){
     case 'add':
       return state+1;
     default:
       return state;  
   }
}
我们调用
<button onClick={()=>dispatch({type:'add'})}>+</button>
useReducer函数里的dispatch函数有参数 而且reducer也是存在的所以 走counterReducer ,render渲染
 
针对上面的hooks问题在工作中也遇到过 三个echarts 图点击上面的放大按钮,点击之后单独弹出一个框里面是绘制好的echart    
我们基于这个场景  肯定是有问题的,原因在于dom没有渲染出来就调用了echarts方法。我们用setTimeout可以模拟异步去解决
本文中我们选择:我们选择将  
import React from 'react';

export default function useForceUpdate() {
  const [, forceUpdate] = React.useReducer(x => x + 1, 0);
  return forceUpdate;
}
其实这个useForceUpdate的方法在于执行之后就可以渲染。渲染就可以  重新进入useEffect里面。也就是重新去绘制echarts
原文地址:https://www.cnblogs.com/MDGE/p/13847836.html