当前位置:   article > 正文

React 18中hook函数详解之useState和useEffect_react18 useeffect

react18 useeffect

前言

React创建组件的方式有三种,分别是函数式组件、类组件,还有createElement组件。react v16.8版本之前函数式组件是没有状态的。但是,自16.8以后得版本有个hook函数,函数式组件也有了状态,反而类组件没有多少人写了,原因在于生命周期很麻烦,也难记。笔者近几年写React项目已经很少使用类组件了。接下来,详细探讨下hook函数,为什么会有那么神奇的效果?

一 、常用的Hook有哪些?

React Hooks 是 React v16.8 之后推出的函数式组件状态管理方案。它是为了解决状态复用、类组件写法麻烦等原因而提出的,Hook函数本质是闭包。Hooks 主要是利用闭包来保存状态,使用链表保存一系列 Hooks,将链表中的第一个 Hook 与 Fiber 关联。在 Fiber 树更新时,就能从 Hooks 中计算出最终输出的状态和执行相关的副作用。Hook函数带来便利有逻辑复用、业务代码更聚合、写法更简洁。

常用的Hook函数useState、useEffect、useRef、useCallback、useMemo、useReducer、useLayoutEffect

二、useState详解

useState是React自带的一个Hook函数,使用useState可声明内部状态变量。useState接收的参数为状态初始值或状态初始化方法,它返回一个数组。数组的第一项是当前状态值,每次渲染其状态值可能都会不同;第二项是可改变对应状态值的set函数,在useState初始化后该函数不会变化。

useState的类型为:

function useState<S>(initialState:S|(() => S )): [S,Dispatch <SetStateAction <S>>];

initialState仅在组件初始化时生效,后续的渲染将忽略initialState:

  1. const [value, setValue] = useState("");
  2. const [count, setCount] = useState(value);

如上例中的value,当初始值传入另一个状态并初始化后,另一个状态函数将不再依赖value的值。

在 class 中,我们需要调用 this.setState() 来更新 count 值,在函数式组件中,我们已经有了 setCount 和 count 变量,所以我们不需要 this:

  1. import {useState} from "react";
  2. const Example = () => {
  3. const [count, setCount] = useState(0);
  4. return (
  5. <div>
  6. <button onClick={() => {setCount(count+1)}}>
  7. 点击更新count:{count}
  8. </button>
  9. </div>
  10. )
  11. }

类似于setState,单击按钮时调用setCount更新了状态值count。当调用setCount后,组件会重新渲染,count的值会得到更新。

当传入初始状态为函数时,其仅执行一次,类似于类组件中的构造函数:

useState返回的更新函数也可使用函数式更新:

setCount(preCount => preCount + 1)

如果新的state需要依赖先前的 state 计算得出,那么可以将回调函数当作参数传递给setState。该回调函数将接收先前的state,并将返回的值作为新的state进行更新。

在组件生命周期或React合成事件中,setState是异步;在setTimeout或者原生dom事件中,setState是同步。

为什么react大部分情况setState是异步的呢?假如所有setState是同步的,意味着每执行一次setState时(有可能一个同步代码中,多次setState),都重新vnode diff + dom修改,这对性能来说是极为不好的。如果是异步,则可以把一个同步代码中的多个setState合并成一次组件更新。

三、useEffect详解

useEffect函数会在组件渲染完毕后,执行和渲染无关的副作用,如数据获取,设置订阅以及手动更改 React 组件中的 DOM 等。

有了useEffect,我们可以在函数组件中实现 像类组件中的生命周期那样某个阶段做某件事情,具有:

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

基本用法:

  1. useEffect(() => {
  2. console.log('这是一个不含依赖数组的useEffect,每次render都会执行!')
  3. })

useEffect接受一个回调函数和一个可选的依赖项数组。回调函数会在组件挂载、更新和卸载时执行,根据依赖项的不同情况选择执行。如果依赖项为空数组,那么回调函数只会在组件挂载和卸载时执行一次。如果依赖项中包含某个状态或属性,那么只有在这个状态或属性发生变化时才会执行回调函数。 

useEffect的规则

  • 没有传第二个参数时,在每次 render 之后都会执行 useEffect中的内容
  • useEffect接受第二个参数来控制跳过执行,下次 render 后如果指定的值没有变化就不会执行
  • useEffect 是在 render 之后浏览器已经渲染结束才执行
  • useEffect 的第二个参数是可选的,类型是一个数组
  • 根据第二个参数的不同情况,useEffect具有不同作用

下面是useEffect的一些常见用法:

1、获取数据和执行网络请求:

  1. import React, { useState, useEffect } from 'react';
  2. import axios from 'axios';
  3. function MyComponent() {
  4. const [data, setData] = useState([]);
  5. useEffect(() => {
  6. const fetchData = async () => {
  7. const result = await axios.get('/api/data');
  8. setData(result.data);
  9. }
  10. fetchData();
  11. }, []);
  12. return (
  13. <div>
  14. {data.map((item) => <div key={item.id}>{item.name}</div>)}
  15. </div>
  16. );
  17. }
  18. export default MyComponent;

2、订阅事件:

  1. import { useEffect } from 'react';
  2. function MyComponent() {
  3. useEffect(() => {
  4. const subscription = myEventEmitter.subscribe('event', () => {
  5. // 处理事件逻辑
  6. });
  7. return () => {
  8. subscription.unsubscribe();
  9. };
  10. }, []);
  11. return <div>My Component</div>;
  12. }

3、执行清理操作:

  1. import { useEffect, useState } from 'react';
  2. function MyComponent() {
  3. const [timer, setTimer] = useState(null);
  4. useEffect(() => {
  5. const id = setInterval(() => {
  6. // 处理定时器逻辑
  7. }, 1000);
  8. setTimer(id);
  9. return () => {
  10. clearInterval(timer);
  11. };
  12. }, []);
  13. return <div>My Component</div>;
  14. }

4、使用第三方库:

  1. import { useEffect } from 'react';
  2. import moment from 'moment';
  3. function MyComponent() {
  4. useEffect(() => {
  5. moment.locale('zh-cn');
  6. }, []);
  7. return <div>{moment().format('LLLL')}</div>;
  8. }

需要注意的是,useEffect回调函数中的操作可能会对应用程序的性能产生影响。如果回调函数执行的操作很耗费资源,那么可能会导致应用程序变慢。因此,需要谨慎使用useEffect,并在需要时进行性能优化。

在使用React Hooks时,需要遵守以下准则及特性要求。

  • 只在顶层使用Hooks。不要在循环、条件或嵌套函数中调用Hooks,确保总是在React函数组件的顶层调用它们。

  • 不要在普通的JavaScript函数中调用Hooks。仅在React的函数组件中调用Hooks,以及在自定义Hook中调用其他Hooks。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/660932
推荐阅读
相关标签
  

闽ICP备14008679号