Hook 是 React 16.8 的新增特性。它可让你在不编写 class 的状况下使用 state 以及其余的 React 特性。html
let memoizedState; //声明memoizedState
function useState(initialState) {
memoizedState = memoizedState || initialState;
function setState(newState) {
memoizedState = newState; //设置状态时候把新状态赋值给memoizedState
render(); //从新render
}
return [memoizedState,setState]
}
复制代码
从简版的实现来看,仍是很容易理解,测试下效果react
用userReducer实现计数器,可接收3个参数,reducer | initalArg(初始值) | init (定义初始值的函数)web
import React,{Fragment,useReducer} from 'react';
import ReactDOM from 'react-dom';
// reducer,跟redux中reducer同样
const INCREMENT = "INCREMENT";
const DECREMENT = "DECREMENT";
function reducer(state,action){
switch (action.type) {
case INCREMENT:
return {number:state.number+1};
case DECREMENT:
return {number:state.number-1};
default:
return state;
}
}
//初始值
let initalArg = 0;
// 返回初始值的函数
function init(initalArg) {
return {number:initalArg};
}
function Counter() {
// state = {number:0}
const [state,dispatch] = useReducer(reducer,initalArg,init);
return (
<Fragment>
<p>{state.number}</p>
<button onClick={()=>dispatch({type:INCREMENT})}>+</button>
<button onClick={()=>dispatch({type:DECREMENT})}>-</button>
</Fragment>
)
}
function render() {
ReactDOM.render(<Counter />,document.getElementById('root'));
}
render();
复制代码
let memoizedState; //声明记忆的状态
function useReducer(reducer,initalArg,init) {
let initialState;
// init若是没有传值,initalArg为默认的初始状态。若是传值,初始值函数处理后做为初始状态
if(typeof init !='undefined'){
initialState = init(initalArg);
}else {
initialState = initalArg;
}
memoizedState = memoizedState || initialState;
function dispatch(action) {
memoizedState = reducer(memoizedState,action);
render();
}
return [memoizedState,dispatch]
}
复制代码
运行结果redux
let memoizedState;
function useReducer(reducer,initalArg,init) {
let initialState;
if(typeof init !='undefined'){
initialState = init(initalArg);
}else {
initialState = initalArg;
}
memoizedState = memoizedState || initialState;
function dispatch(action) {
memoizedState = reducer(memoizedState,action);
render();
}
return [memoizedState,dispatch]
}
function useState(initialState) {
// 主要是reducer实现,把新状态赋值过去
return useReducer((oldState,newState)=>newState,initialState);
}
复制代码
验证如下数组
当一个组件调用多个useState时,此时咱们须要用数组来保存多个初始值缓存
import React,{Fragment} from 'react';
import ReactDOM from 'react-dom';
// 数组保存memoizedState
let memoizedState=[];
// 记录索引
let index = 0;
function useState(initialState) {
memoizedState[index] = memoizedState[index] || initialState;
// 缓存当前索引,由于每次render,index索引会重置为0
let currentIndex = index;
function setState(newState) {
memoizedState[currentIndex] = newState;
render();
}
return [memoizedState[index++],setState]
}
function Counter() {
const [name,setName] = useState('计数器');
const [number,setNumber] = useState(0);
return (
<Fragment>
<p>{name }:{number}</p>
<button onClick={()=>setName("计数器"+Date.now())}>更名称</button>
<button onClick={()=>setNumber(number+1)}>+</button>
</Fragment>
)
}
function render() {
// 每次render,把index回复初始值
index = 0;
ReactDOM.render(<Counter />,document.getElementById('root'));
}
render();
复制代码
看下效果,源码是用链表实现的,此处咱们用数组,逻辑是差很少,容易理解bash
计数器变化后,实现打印一句log的示例 参考连接dom
import React,{Fragment,useState} from 'react';
import ReactDOM from 'react-dom';
function Counter() {
const [name,setName] = useState('计数器');
const [number,setNumber] = useState(0);
useEffect(()=>{
// 订阅
console.log("订阅状态")
},[number,name]);
return (
<Fragment>
<p>{name }:{number}</p>
<button onClick={()=>setName("计数器"+Date.now())}>更名称</button>
<button onClick={()=>setNumber(number+1)}>+</button>
</Fragment>
)
}
function render() {
ReactDOM.render(<Counter />,document.getElementById('root'));
}
render();
复制代码
简版实现函数
// 记录最后依赖项
let lastDependencies;
function useEffect(callback,dependencies) {
// 若是依赖项没有传值,则直接调用callback
if(!dependencies) return callback();
/* 一、首次渲染isChange为true,把初始的依赖项赋给lastDependencies
* 二、再次渲染时候,把lastDependencies和dependencies作对比,当不彻底相等时,才触发回调
*/
let isChange = lastDependencies? !dependencies.every((item,index)=>item===lastDependencies[index]):true;
if(isChange){
callback();
lastDependencies = dependencies;
}
}
复制代码
let memoizedState=[];
let index = 0;
function useState(initialState) {
memoizedState[index] = memoizedState[index] || initialState;
let currentIndex = index;
function setState(newState) {
memoizedState[currentIndex] = newState;
render();
}
return [memoizedState[index++],setState]
}
function useEffect(callback,dependencies) {
console.log('dependencies',dependencies);
// 若是依赖项没有传值,则直接调用callback
if(!dependencies){
// 保证索引对应
index++;
return callback();
}
// 从memoizedState取最后一个依赖项
let lastDependencies = memoizedState[index];
let isChange = lastDependencies? !dependencies.every((item,index)=>item===lastDependencies[index]):true;
if(isChange){
callback();
// 往memoizedState存依赖项
memoizedState[index] = dependencies;
}
// 索引递增
index++
}
复制代码
验证下效果测试
后续继续补充