要知道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