使用useEffect模拟组件生命周期

 更新时间:2022年09月14日 16:55:34   作者:景尘  
这篇文章主要介绍了使用useEffect模拟组件生命周期,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

useEffect模拟组件生命周期

让函数组件模拟生命周期

  • 默认函数组件没有生命周期
  • 函数组件是一个纯函数,执行完即销毁,自己无法实现生命周期
  • 通过Effect hook把生命周期“钩”到纯函数中
    // 模拟 class 组件的 DidMount 和 DidUpdate
    useEffect(() => {
      console.log('在此发送一个 ajax 请求')
    })
 
    // // 模拟 class 组件的 DidMount
     useEffect(() => {
        console.log('加载完了')
     }, []) // 第二个参数是 [] (不依赖于任何 state)
 
     // 模拟 class 组件的 DidUpdate
     useEffect(() => {
         console.log('更新了')
     }, [count, name]) // 第二个参数就是依赖的 state
 
    // 模拟 class 组件的 DidMount
    useEffect(() => {
        let timerId = window.setInterval(() => {
            console.log(Date.now())
        }, 1000)
 
        // 返回一个函数
        // 模拟 WillUnMount 组件销毁的时候 停止计时器
        return () => {
            window.clearInterval(timerId)
        }
    }, [])

总结:

  • 模拟componentDidMount  -  useEffect 依赖 [ ]
  • 模拟compenentDidUpdate - useEffect 无依赖 ,或者 依赖 [a,b,c]
  • 模拟componentWillUnMount - useEffect 中返回一个函数

react在16.8之后有了新特性 react hooks

之前的主要的生命周期为:

初始化

在组件初始化阶段会执行

  • constructor
  • componentWillMount() 
  • render()
  • componentDidMount()

更新阶段

props或state的改变可能会引起组件的更新,组件重新渲染的过程中会调用以下方法:

  • componentWillReceiveProps()
  • shouldComponentUpdate()
  • componentWillUpdate() 
  • render()
  • componentDidUpdate()

卸载阶段

  • componentWillUnmount()

useEffect实现componentWillUnmount生命周期函数

阐述

在写React应用的时候,在组件中经常用到 componentWillUnmount 生命周期函数(组件将要被卸载时执行)。比如我们的定时器要清空,避免发生内存泄漏;比如登录状态要取消掉,避免下次进入信息出错。

所以这个生命周期函数也是必不可少的,本文就用 useEffect 来实现这个生命周期函数,并讲解一下 useEffect 容易踩的坑。

useEffect 解绑副作用

学习React Hooks 时,我们要改掉生命周期函数的概念,因为Hooks叫它副作用,所以componentWillUnmount也可以理解成解绑副作用。

这里为了演示用useEffect来实现类似componentWillUnmount效果,先安装React-Router路由,进入项目根本录,使用npm进行安装。

npm install --save react-router-dom@5.2.0

然后打开 Example.js 文件,进行改写代码,先引入对应的React-Router组件。

import { BrowserRouter as Router, Route, Link } from "react-router-dom"

在文件中编写两个新组件,因为这两个组件都非常的简单,所以就不单独建立一个新的文件来写了。

function Index() {
    return <h2>willem</h2>;
}
function List() {
    return <h2>List-Page</h2>;
}

有了这两个组件后,接下来可以编写路由配置,在以前的计数器代码中直接增加就可以了。

function Example(){
    const [count, setCount] = useState(0);
    return ( 
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()=>{setCount(count + 1)}}>Chlick me</button>
            <Router>
                <ul>
                    <li><Link to="/">首页</Link> </li>
                    <li><Link to="/list/">列表</Link> </li>
                </ul>
                <Route path="/" exact component={Index} />
                <Route path="/list/" component={List} />
            </Router>
        </div>
    );
}

然后到浏览器中查看一下,看看组件和路由是否可用。

如果可用,我们现在可以调整useEffect了。

在这里插入图片描述

在两个新组件中分别加入useEffect()函数:

function Index() {
    useEffect(()=>{
        console.log('useEffect=>我是 Index页面')
    })
    return <h2>willem</h2>;
}
function List() {
    useEffect(()=>{
        console.log('useEffect=>我是 List页面')
    })
    return <h2>List-Page</h2>;
}

这时候我们点击Link进入任何一个组件,在浏览器中都会打印出对应的一段话。这时候可以用返回一个函数的形式进行解绑,代码如下:

function Index() {
    useEffect(()=>{
        console.log('useEffect=>我是Index页面')
        return ()=>{
            console.log('你走了 Index页面')
        }
    })
    return <h2>willem</h2>;
}

这时候你在浏览器中预览,我们仿佛实现了 componentWillUnmount方法。

但这只是好像实现了,当点击计数器按钮时,你会发现你走了Index页面,也出现了。

这到底是怎么回事那?

其实每次状态发生变化,useEffect都进行了解绑。

在这里插入图片描述

ReactHooksDemo\demo01\src\Example.js

import React, { useState, useEffect } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom"
function Index() {
    useEffect(()=>{
        console.log('useEffect=>我是Index页面')
        return ()=>{
            console.log('你走了 Index页面')
        }
    },[])
    return <h2>willem</h2>;
}
function List() {
    useEffect(()=>{
        console.log('useEffect=>我是 List页面')
    })
    return <h2>List-Page</h2>;
}
function Example(){
    const [count, setCount] = useState(0);
    return ( 
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()=>{setCount(count + 1)}}>Chlick me</button>
            <Router>
                <ul>
                    <li><Link to="/">首页</Link> </li>
                    <li><Link to="/list/">列表</Link> </li>
                </ul>
                <Route path="/" exact component={Index} />
                <Route path="/list/" component={List} />
            </Router>
        </div>
    );
}
export default Example;

useEffect的第二个参数

那到底要如何实现类似 componentWillUnmount的效果那?

这就需要请出useEffect的第二个参数,它是一个数组,数组中可以写入很多状态对应的变量,意思是当状态值发生变化时,我们才进行解绑。

但是当传空数组 [] 时,就是当组件将被销毁时才进行解绑,这也就实现了componentWillUnmount的生命周期函数。

function Index() {
    useEffect(()=>{
        console.log('useEffect=>我是Index页面')
        return ()=>{
            console.log('你走了 Index页面')
        }
    },[])
    return <h2>willem</h2>;
}

为了更加深入了解第二个参数的作用,把计数器的代码也加上 useEffect 和解绑方法,并加入第二个参数为空数组。

代码如下:

ReactHooksDemo\demo01\src\Example.js

function Example(){
    const [count, setCount] = useState(0);
    useEffect(()=>{
        console.log(`useEffect=>You clicked ${count} times`)
        return ()=>{
            console.log('====================')
        }
    },[])
    return ( 
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()=>{setCount(count + 1)}}>Chlick me</button>
            <Router>
                <ul>
                    <li><Link to="/">首页</Link> </li>
                    <li><Link to="/list/">列表</Link> </li>
                </ul>
                <Route path="/" exact component={Index} />
                <Route path="/list/" component={List} />
            </Router>
        </div>
    );
}

这时候的代码是不能执行解绑副作用函数的。

但是如果我们想每次count发生变化,我们都进行解绑,只需要在第二个参数的数组里加入count变量就可以了。

代码如下:

function Example(){
    const [count, setCount] = useState(0);
    useEffect(()=>{
        console.log(`useEffect=>You clicked ${count} times`)
        return ()=>{
            console.log('====================')
        }
    },[count])
    return ( 
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()=>{setCount(count + 1)}}>Chlick me</button>
            <Router>
                <ul>
                    <li><Link to="/">首页</Link> </li>
                    <li><Link to="/list/">列表</Link> </li>
                </ul>
                <Route path="/" exact component={Index} />
                <Route path="/list/" component={List} />
            </Router>
        </div>
    );
}

这时候只要count状态发生变化,都会执行解绑副作用函数,浏览器的控制台也就打印出了一串=================。

在这里插入图片描述

总结

通过对本文的学习,让我们对useEffect函数有了一个比较深入的了解,并且可以通过useEffect实现生命周期函数了,现在用React Hooks这种函数的方法编写组件,对比以前用Class编写组件几乎一样了。

ReactHooksDemo\demo01\src\index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Example from './Example';
ReactDOM.render(<Example />, document.getElementById('root'));

ReactHooksDemo\demo01\src\Example.js

import React, { useState, useEffect } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom"
function Index() {
    useEffect(()=>{
        console.log('useEffect=>我是Index页面')
        return ()=>{
            console.log('你走了 Index页面')
        }
    },[])
    return <h2>willem</h2>;
}
function List() {
    useEffect(()=>{
        console.log('useEffect=>我是 List页面')
    })
    return <h2>List-Page</h2>;
}
function Example(){
    const [count, setCount] = useState(0);
    useEffect(()=>{
        console.log(`useEffect=>You clicked ${count} times`)
        return ()=>{
            console.log('====================')
        }
    },[count])
    return ( 
        <div>
            <p>You clicked {count} times</p>
            <button onClick={()=>{setCount(count + 1)}}>Chlick me</button>
            <Router>
                <ul>
                    <li><Link to="/">首页</Link> </li>
                    <li><Link to="/list/">列表</Link> </li>
                </ul>
                <Route path="/" exact component={Index} />
                <Route path="/list/" component={List} />
            </Router>
        </div>
    );
}
export default Example;

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。 

相关文章

  • React Fiber树的构建和替换过程讲解

    React Fiber树的构建和替换过程讲解

    React Fiber树的创建和替换过程运用了双缓存技术,直接将旧的 fiber 树替换成新的 fiber 树,这样做的好处是省去了直接在页面上渲染时的计算时间,避免计算量大导致的白屏、卡顿,现在你一定还不太理解,下面进行详细讲解,需要的朋友可以参考下
    2022-12-12
  • React 条件渲染最佳实践小结(7种)

    React 条件渲染最佳实践小结(7种)

    这篇文章主要介绍了React 条件渲染最佳实践小结(7种),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • React Fiber 树思想解决业务实际场景详解

    React Fiber 树思想解决业务实际场景详解

    这篇文章主要为大家介绍了React Fiber 树思想解决业务实际场景详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • webpack 2的react开发配置实例代码

    webpack 2的react开发配置实例代码

    本篇文章主要介绍了webpack 2的react开发配置实例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • React createRef循环动态赋值ref问题

    React createRef循环动态赋值ref问题

    这篇文章主要介绍了React createRef循环动态赋值ref问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • 在react中使用highlight.js将页面上的代码高亮的方法

    在react中使用highlight.js将页面上的代码高亮的方法

    本文通过 highlight.js 库实现对文章正文 HTML 中的代码元素自动添加语法高亮,具有一定的参考价值,感兴趣的可以了解一下
    2022-01-01
  • 详解Jotai Immer如何实现undo redo功能示例详解

    详解Jotai Immer如何实现undo redo功能示例详解

    这篇文章主要为大家介绍了详解Jotai Immer如何实现undo redo功能示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • 解决React报错useNavigate() may be used only in context of Router

    解决React报错useNavigate() may be used only in context of

    这篇文章主要为大家介绍了解决React报错useNavigate() may be used only in context of Router,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • React使用useImperativeHandle自定义暴露给父组件的示例详解

    React使用useImperativeHandle自定义暴露给父组件的示例详解

    useImperativeHandle 是 React 提供的一个自定义 Hook,用于在函数组件中显式地暴露给父组件特定实例的方法,本文将介绍 useImperativeHandle的基本用法、常见应用场景,需要的可以参考下
    2024-03-03
  • 使用Jenkins部署React项目的方法步骤

    使用Jenkins部署React项目的方法步骤

    这篇文章主要介绍了使用Jenkins部署React项目的方法步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03

最新评论