關于原生的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'));
複制代碼