关于原生的useEffect的基本用法,可以看我的这篇文章 这一次,彻底搞懂useEffect ,简洁易懂。
原生useEffect具备的几个特点
- useEffect可以多次调用。
- useEffect根据传入参数的不同,具有不同的执行方法。
手写useEffect的步骤
第一步:使用数组来存储不同的effect
// 以前的依赖值
let preArray = [];
// 定义effect的索引
let effectId = 0;
复制代码
第二步:判断传入参数是否正确
- 如果第一个参数传入的不是函数则报错
// 如果第一个参数不是一个函数则报错
if (Object.prototype.toString.call(callback) !== '[object Function]') {
throw new Error('第一个参数不是函数')
}
复制代码
- 判断第二个参数
-
- 没传的话,按照componentDidMount 和 componentDidUptate处理
- 传的话,判读是不是数组,不是则报错
- 获取前一个effect,如果没有则等同于compoentDidMout,直接执行callback,如果有则判断是否与以前的依赖值一样,如果不一样则执行callback,这样就实现了第二个参数数组内的元素发生变化的时候才执行callback.
// 如果第二个参数不传,相当于componentDidMount和componentDidUpdate
if (typeof array === 'undefined') {
callback();
} else {
// 判断array是不是数组
if (Object.prototype.toString.call(array) !== '[object Array]') throw new Error('useEffect的第二个参数必须是数组')
// 获取前一个的effect
if (preArray[effectId]) {
// 判断和以前的依赖值是否一致,一致则执行callback
let hasChange = array.every((item,index) => item === preArray[effectId][index]) ? false : true;
if (hasChange) {
callback();
}
} else {
callback()
}
复制代码
第三步:更新依赖值
注意,本次实现的useEffect是需要render函数执行的时候,将effectId置为0的。
// 更新依赖值
preArray[effectId] = array;
effectId++;
复制代码
全部代码
import React from 'react'
import ReactDOM from 'react-dom'
// 自定义Hook
// 自定义useState
let states = [];
let setters = [];
let stateid = 0;
function render() {
stateid = 0;
effectId = 0;
ReactDOM.render(<App />,document.querySelector('#root'));
}
function createSetter(stateid) {
return function (newState) {
states[stateid] = newState;
render()
}
}
function myUseState(initialState) {
states[stateid] = states[stateid] ? states[stateid] : initialState;
setters.push(createSetter(stateid));
let value = states[stateid];
let setter = setters[stateid];
stateid++;
return [value,setter]
}
// 以前的依赖值
let preArray = [];
// 定义effect的索引
let effectId = 0;
function myUseEffect(callback,array) {
// 如果第一个参数不是一个函数则报错
if (Object.prototype.toString.call(callback) !== '[object Function]') {
throw new Error('第一个参数不是函数')
}
// 如果第二个参数不传,相当于componentDidMount和componentDidUpdate
if (typeof array === 'undefined') {
callback();
} else {
// 判断array是不是数组
if (Object.prototype.toString.call(array) !== '[object Array]') throw new Error('useEffect的第二个参数必须是数组')
// 获取前一个的effect
if (preArray[effectId]) {
// 判断和以前的依赖值是否一致,一致则执行callback
let hasChange = array.every((item,index) => item === preArray[effectId][index]) ? false : true;
if (hasChange) {
callback();
}
} else {
callback()
}
// 更新依赖值
preArray[effectId] = array;
effectId++;
}
}
function App() {
const [count,setCount] = myUseState(0);
const [name,setName] = myUseState('张三');
myUseEffect(() => {
console.log('这是count');
},[count]);
myUseEffect(() => {
console.log('这是name');
},[name]);
return (
<div>
<h1>当前求和为:{count}</h1>
<button onClick={() => setCount(count + 1)}>点我+1</button>
<h1>当前姓名为:{name}</h1>
<button onClick={() => setName('李四')}>点我修改姓名</button>
</div>
)
}
ReactDOM.render(<App />, document.querySelector('#root'));
复制代码