关于原生的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')); 复制代码