这一次,学会手写useEffect

简介: 这一次,学会手写useEffect

关于原生的useEffect的基本用法,可以看我的这篇文章这一次,彻底搞懂useEffect,简洁易懂。

原生useEffect具备的几个特点

  1. useEffect可以多次调用。
  2. 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'));
复制代码

在线实现

相关文章
|
18天前
|
存储 JavaScript
实现vuex源码,手写
实现vuex源码,手写
|
6月前
|
存储 缓存 JavaScript
手写简单Redux
手写简单Redux
|
6月前
|
前端开发 JavaScript API
手写promise
手写promise
40 0
|
前端开发
手写防抖
手写防抖
61 0
|
6月前
|
前端开发 JavaScript UED
手写一个防抖
手写一个防抖
41 0
|
前端开发
react手写全选反选
react手写全选反选
92 0
react手写全选反选
|
缓存 移动开发 前端开发
10分钟教你手写8个常用的自定义hooks
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。本文是一篇以实战为主的文章,主要讲解实际项目中如何使用hooks以及一些最佳实践,不会一步步再介绍一遍react hooks的由来和基本使用,因为写hooks的文章很多,而且官网对于react hooks的介绍也很详细,所以大家不熟悉的可以看一遍官网。
495 0
|
前端开发
手写Promise
手写Promise
|
前端开发 容器
简单手写实现react的函数组件
简单手写实现react的函数组件
164 0
|
前端开发 JavaScript
简单手写实现React的基本生命周期
简单手写实现React的基本生命周期
133 0