02react 函数组件useState的异步问题

这篇具有很好参考价值的文章主要介绍了02react 函数组件useState的异步问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

react 函数组件

常见的钩子函数:useState、useEffect

useState的异步

useState作为最常见的一个hook,在使用中总是会出现各种坑,最明显的就是 useState 更新异步的问题。

  • 问题描述:把接口返回的数据,使用 useState 储存起来,但是当后面去改变这个数据的时候,每次拿到的都是上次的数据,无法实时更新。或者我们在函数内部使用 setState ,然后立即打印 state,打印的结果还是第一次的state 的值。
  • 原因:useState 返回的更新对象的方法是异步的,要在下次重绘才能获取新值,不要试图在更改状态之后立即获取状态。
  • 控制台报错:
    react usestate set值异步,react,react.js,前端,javascript
  • 代码,函数组件:
import React, { useState, useEffect } from 'react';
import styles from './index.less';
export default function index({ content = {} }) {
  const [data, setData] = useState([]);
  useEffect(() => {
    if (content !== null) {
      const myModityData = content.title.split('***');
      setData(myModityData);
    }
  }, [content.title]);
  return (
    <div className={styles.home_box}>
      <div className={styles.title}>{data[0]}</div>
      <div className={styles.titleBottom}>{data[1]}</div>
      <p className={styles.des}>{content.des}</p>
    </div>
  );
}

原因总结:

这是因为React里事件分为合成事件和原生事件,合成事件和钩子函数都是异步的,原生事件是同步的。因为useState是异步事件,所以会出现不能及时获取到最新值的情况。
useState 返回的更新状态方法是异步的,要在下次重绘才能获取新值。不要试图在更改状态之后立马获取状态。
注意:useEffect的第二个参数,我表明监听content.title但还是不行,因为在React的函数组件中使用useState进行数据存储,导致数据异步,不能及时获取当前最新的数据。

解决办法思路:

  • 办法一:先使用useRef进行存储数据,再使用useEffect监听数据变化,并进行更新。
    在之后需要使用 info 数据的地方只需要获取 infoRef.current 即可获取最新的 info 数据内容。
import React, { useState, useEffect, useRef } from 'react';

const Index = () => {
	const [info, setInfo] = useState()
	const infoRef = useRef()
	useEffect(() => {
		infoRef.current = info
	}, [info])
}

  • 办法二:使用回调函数更改数据
  • useState 使用的两种方式
    我们知道,useState中的 [ ] 是一个解构运算,第一个是设置的值,第二个是用来改变 state 的方法。
    一般情况下,我们使用第一种方式即可,但在某些特殊情况下,第一种方式获取到的值不是最新设置的。
const [data, setData] = useState(1)
setData(data + 1)
const [data, setData] = useState(0)
setData((prev) => prev + 1); // prev 是data 改变之前的值,return 返回的值会作为新状态覆盖data

原文链接:React hooks中 useState踩坑——异步问题

实际解决办法:

办法一:页面能渲染出来,但控制台报错,监听会一直存在,很耗能

控制台报错:
react usestate set值异步,react,react.js,前端,javascript
中文解释:警告:超过了最大更新深度。当组件在useEffect内部调用setState时,可能会发生这种情况,但useEffect要么没有依赖关系数组,要么依赖关系在每次渲染时都会发生变化。

代码:
react usestate set值异步,react,react.js,前端,javascript

完整代码:

const UAVEdge = (props) => {
  const { UAVEdgeModel, dispatch } = props;
  const { productLists, typeId, page } = UAVEdgeModel;
  const [data, setData] = useState(productLists);
  const myRef = useRef();
  useEffect(() => {
    myRef.current = data;
    const myDeleteData = myRef.current.slice(0, 1);
    setData(myDeleteData);
  }, [data]);
  useEffect(() => {
    dispatch({
      type: 'UAVEdgeModel/getProductList',
    });
  }, []);
  return (
    <>
      <Banner content={uavDate} />
      <Content content={data} />
      <Content02 content={productLists} />
      {/* <Swiper /> */}
    </>
  );
};
export default connect(({ UAVEdgeModel }) => ({
  UAVEdgeModel,
}))(UAVEdge);

办法二:useState(使用回调函数)

控制台报错:
react usestate set值异步,react,react.js,前端,javascript
中文解释:
未捕获错误:重新渲染过多。React限制渲染次数,以防止无限循环。
代码:
react usestate set值异步,react,react.js,前端,javascript

完整代码:

import React, { useState, useEffect } from 'react';
import styles from './index.less';
export default function index({ content = [] }) {
  const [data, setData] = useState(content);
  setData((prev) => {
    const myDeleteData = prev.slice(1, 5);
    return myDeleteData
  })
  return (
    <div className={styles.home_box}>
      <div className={styles.home_container}>
        {data.map((item) => {
          return (
            <div className={styles.edge_box} key={item.id}>
              <div className={styles.boxContainer}>
                <img src={item.img} alt="一张图" />
                <div className={styles.title}>{item.title}</div>
                <p className={styles.des}>{item.des}</p>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

办法三:办法一的改进

代码:
react usestate set值异步,react,react.js,前端,javascript

完整代码:

import React, { useState, useEffect, useRef } from 'react';
import styles from './index.less';
export default function index({ content = [] }) {
  const [data, setData] = useState(content);
  const myRef = useRef();
  useEffect(() => {
    const myDeleteData = data.slice(1, 5);
    myRef.current = myDeleteData;
  }, [data]);
  return (
    <div className={styles.home_box}>
      <div className={styles.home_container}>
        {myRef.current?.map((item) => {
          return (
            <div className={styles.edge_box} key={item.id}>
              <div className={styles.boxContainer}>
                <img src={item.img} alt="一张图" />
                <div className={styles.title}>{item.title}</div>
                <p className={styles.des}>{item.des}</p>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

办法四:组件传参的时候,传数据

思路:组件传参的时候,传数据
控制台报错:
react usestate set值异步,react,react.js,前端,javascript
中文解释:
需要独一无二的key。可是我明明已经给了,为什么?
接口返回的数据:
react usestate set值异步,react,react.js,前端,javascript
函数组件传参,代码:
react usestate set值异步,react,react.js,前端,javascript

函数组件传参,完整代码:

const UAVEdge = (props) => {
  const { UAVEdgeModel, dispatch } = props;
  const { productLists, typeId, page } = UAVEdgeModel;
  useEffect(() => {
    dispatch({
      type: 'UAVEdgeModel/getProductList',
    });
  }, []);
  return (
    <>
      <Banner content={uavDate} />
      <Content content={[productLists[0] || {}]} />
      <Content02 content={productLists} />
      {/* <Swiper /> */}
    </>
  );
};
export default connect(({ UAVEdgeModel }) => ({
  UAVEdgeModel,
}))(UAVEdge);

办法五:办法四的加强版

思路:把数据处理干净传过去,使用useRef()处理数据
代码:
react usestate set值异步,react,react.js,前端,javascript

完整代码:

const GroundEdge = (props) => {
  const { GroundEdgeModel, dispatch } = props;
  const { productLists, typeId, page } = GroundEdgeModel;
  const [data, setData] = useState(productLists);
  const myRef = useRef()
  useEffect(() => {
    const myDeleteData = data.slice(0,1);    
    myRef.current = myDeleteData
  }, [data]);
  useEffect(() => {
    dispatch({
      type: 'GroundEdgeModel/getProductList',
    });
  }, []);
  return (
    <>
      <Banner content={groDate} />
      <Content content={myRef.current} />
      <Content02 content={productLists} />
      {/* <Swiper /> */}
    </>
  );
};
export default connect(({ GroundEdgeModel }) => ({
  GroundEdgeModel,
}))(GroundEdge);

办法六:办法五的加强版

期望后端接口数据:
react usestate set值异步,react,react.js,前端,javascript

实际后端接口数据:
react usestate set值异步,react,react.js,前端,javascript

代码:
react usestate set值异步,react,react.js,前端,javascript

完整代码:

const OnboardEdge = (props) => {
  const { OnboardEdgeModel, dispatch } = props;
  const { productLists, typeId, page } = OnboardEdgeModel;
  const [info, setInfo] = useState(productLists);
  let infoRef = useRef();
  useEffect(() => {
    if (productLists !== null) {
      const myModityData = info.map((item) => {
        return {
          ...item,
          title: item.title.split('***'),
        };
      });
      infoRef.current = myModityData[0];
    }
  }, [info]);

  useEffect(() => {
    dispatch({
      type: 'OnboardEdgeModel/getProductList',
    });
  }, []);

  return (
    <div className={styles.home_box}>
      <Banner content={onbDate} />
      {/* <PageTitleThreeC content={productLists[0] || {}} /> */}
      <PageTitleThreeC content={infoRef.current} />
      <Content01 content={productLists[0]} />
      <Content02 content={productLists} />
      {/* <Swiper /> */}
    </div>
  );
};
export default connect(({ OnboardEdgeModel }) => ({
  OnboardEdgeModel,
}))(OnboardEdge);

推荐使用:办法三useRef()

终极简单:不解决异步问题

之前解决了那么多,但useState在项目实际中依然没有解决。
终极简单思路:处理“干净的”数据传给组件,再传递的时候进行一个数组对象的截取react适用,vue没有实践过。
处理前:
react usestate set值异步,react,react.js,前端,javascript
处理后:
react usestate set值异步,react,react.js,前端,javascript
字符串转数组:
期待把后端的数据title字段进行一个split()截取
react usestate set值异步,react,react.js,前端,javascript

import React, { useState, useEffect, useRef } from 'react';
import styles from './index.less';
export default function index({ content = {} }) {
  let arr = [];
  if (content.title) {
    let title = content.title;
    arr = title.split('***');
  }
  return (
    <div className={styles.home_box}>
      <div className={styles.title}>{arr[0]}</div>
      <div className={styles.titleBottom}>{arr[1]}</div>
      <p className={styles.des}>{content.des}</p>
    </div>
  );
}

总结:

大道求简。在写的过程中,一点一点完善,发现到了最后,有更加简单的方法,根本不用走那一套。
你要问我有没有意义,仁者见仁。文章来源地址https://www.toymoban.com/news/detail-769733.html

到了这里,关于02react 函数组件useState的异步问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • React -- useState使用方法

    userState 是一个React Hook (函数)。它允许我们向组件添加一个状态变量,从而控制影响组件的渲染结果 1. useState是一个函数,返回值是一个数组 2. 数组中第一个参数是状态变量,第二个参数是set开头的函数名,用于修改变量 3. useState的参数作为count的初始值 4.使用举例

    2024年02月19日
    浏览(26)
  • [react] useState的一些小细节

    因为setState修改是异步的,加上会触发函数重新渲染, 如果代码长这样  一秒再修改,然后重新触发setTImeout, 然后再触发,重复触发循环 如果这样呢 还是会,因为你执行又会重新渲染  为什么修改多次还是跟不上呢? 因为是异步修改 ,所以会出现问题,怎么办?用传函数的形式解决 C

    2024年04月13日
    浏览(30)
  • React源码解析18(6)------ 实现useState

    在上一篇文章中,我们已经实现了函数组件。同时可以正常通过render进行渲染。 而通过之前的文章,beginWork和completeWork也已经有了基本的架子。现在我们可以去实现useState了。 实现之前,我们要先修改一下我们的index.js文件: 由于我们这一篇并不会实现React的事件机制,所以

    2024年02月13日
    浏览(21)
  • React Hooks的useState、useRef使用

    React Hooks 是 React 16.8 版本引入的新特性,它允许你在不编写 class 的情况下使用 state 和其他 React 特性。其中, useState  和  useRef  是两个常用的 Hooks。 1. useState useState  是一个允许你在函数组件中添加 state 的 Hook。 使用说明: useState  返回一个状态变量和一个设置该变量的函

    2024年02月02日
    浏览(30)
  • react中的useState和useImmer的用法

    react中文官网教程 在函数式组件中,可以使用 useState 这个 Hook 来定义和管理组件的状态。 useState 接受一个初始状态作为参数,并返回一个包含 state 和更新 state 的方法的数组。 下面是一个例子,展示了如何在函数式组件中定义自己的 state: 在上面的例子中,我们使用 useStat

    2024年02月07日
    浏览(36)
  • 解决useState 异步回调useGetState自定义hooks获取不到最新值

    1、直接传入新值 setState(options); 2、传入回调函数 setState(callBack); 通常情况下 setState 直接使用上述第一种方式传参即可,但在一些特殊情况下第一种方式会出现异常; 例如希望在异步回调或闭包中获取最新状态并设置状态,此时第一种方式获取的状态不是实时的,React 官方文

    2024年02月06日
    浏览(36)
  • react中useState、setState、usemeno、meno区别

    useState和setState是异步 useState : useState 是React函数组件中的钩子,用于声明状态变量。 通过 useState ,你可以在函数组件中添加状态,而无需创建类组件。 useState 返回一个数组,其中包含当前状态和一个更新状态的函数 setState : setState 是类组件中用于更新状态的方法。 在类

    2024年02月22日
    浏览(25)
  • react18中,useState 和 useEffect有什么区别

    useState 目的:useState用于在函数组件中添加状态。之前,只有类组件才能有自己的状态,但useState钩子使得函数组件也能够利用React的状态特性。 使用场景:当你需要在组件中存储、读取或更新一些数据时使用。例如,控制输入框的内容、切换按钮的状态等。 工作原理:useS

    2024年02月19日
    浏览(31)
  • react中useState的值没有改变,而是旧的数值

    想实现点击按钮就改变数据的效果,但是在控制台的打印结果,总是上一次的修改情况,并不是最新的修改后的数据 代码: 在 React 中, useState 是一个异步更新状态的 Hook,因此在调用 setAName 更新状态后, sonAName 并不会立即改变,而是会在下一次渲染时才会更新。 因此,在

    2024年04月26日
    浏览(23)
  • react useState useEffect useMemo实际业务场景中的使用

    下面的代码实现了上面图片的功能

    2024年02月16日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包