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

useState的异步问题

  • react 函数组件
    • useState的异步
    • 原因总结:
    • 解决办法思路:
    • 实际解决办法:
      • 办法一:页面能渲染出来,但控制台报错,监听会一直存在,很耗能
      • 办法二:useState(使用回调函数)
      • 办法三:办法一的改进
      • 办法四:组件传参的时候,传数据
      • 办法五:办法四的加强版
      • 办法六:办法五的加强版
      • 推荐使用:办法三useRef()
      • 终极简单:不解决异步问题
      • 总结:

react 函数组件

常见的钩子函数:useState、useEffect

useState的异步

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

  • 问题描述:把接口返回的数据,使用 useState 储存起来,但是当后面去改变这个数据的时候,每次拿到的都是上次的数据,无法实时更新。或者我们在函数内部使用 setState ,然后立即打印 state,打印的结果还是第一次的state 的值。
  • 原因:useState 返回的更新对象的方法是异步的,要在下次重绘才能获取新值,不要试图在更改状态之后立即获取状态。
  • 控制台报错:

    在这里插入图片描述

  • 代码,函数组件:
import React, https://blog.csdn.net/weixin_45024453/article/details/{ useState, useEffect } from 'react';import styles from './index.less';export default function index(https://blog.csdn.net/weixin_45024453/article/details/{ content = https://blog.csdn.net/weixin_45024453/article/details/{} }) https://blog.csdn.net/weixin_45024453/article/details/{  const [data, setData] = useState([]);  useEffect(() => https://blog.csdn.net/weixin_45024453/article/details/{    if (content !== null) https://blog.csdn.net/weixin_45024453/article/details/{      const myModityData = content.title.split('***');      setData(myModityData);    }  }, [content.title]);  return (    styles.home_box}>      styles.title}>https://blog.csdn.net/weixin_45024453/article/details/{data[0]}      styles.titleBottom}>https://blog.csdn.net/weixin_45024453/article/details/{data[1]}      <p className=https://blog.csdn.net/weixin_45024453/article/details/{styles.des}>https://blog.csdn.net/weixin_45024453/article/details/{content.des}

); }

原因总结:

这是因为React里事件分为合成事件和原生事件,合成事件和钩子函数都是异步的,原生事件是同步的。因为useState是异步事件,所以会出现不能及时获取到最新值的情况。

useState 返回的更新状态方法是异步的,要在下次重绘才能获取新值。不要试图在更改状态之后立马获取状态。

注意:useEffect的第二个参数,我表明监听content.title但还是不行,因为在React的函数组件中使用useState进行数据存储,导致数据异步,不能及时获取当前最新的数据。

解决办法思路:

  • 办法一:先使用useRef进行存储数据,再使用useEffect监听数据变化,并进行更新。

    在之后需要使用 info 数据的地方只需要获取 infoRef.current 即可获取最新的 info 数据内容。

import React, https://blog.csdn.net/weixin_45024453/article/details/{ useState, useEffect, useRef } from 'react';const Index = () => https://blog.csdn.net/weixin_45024453/article/details/{	const [info, setInfo] = useState()	const infoRef = useRef()	useEffect(() => https://blog.csdn.net/weixin_45024453/article/details/{		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踩坑——异步问题

实际解决办法:

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

控制台报错:

在这里插入图片描述

中文解释:警告:超过了最大更新深度。当组件在useEffect内部调用setState时,可能会发生这种情况,但useEffect要么没有依赖关系数组,要么依赖关系在每次渲染时都会发生变化。

代码:

在这里插入图片描述

完整代码:

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

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

控制台报错:

在这里插入图片描述

中文解释:

未捕获错误:重新渲染过多。React限制渲染次数,以防止无限循环。

代码:

在这里插入图片描述

完整代码:

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

); })} ); }

办法三:办法一的改进

代码:

在这里插入图片描述

完整代码:

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

); })} ); }

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

思路:组件传参的时候,传数据

控制台报错:

在这里插入图片描述

中文解释:

需要独一无二的key。可是我明明已经给了,为什么?

接口返回的数据:

在这里插入图片描述

函数组件传参,代码:

在这里插入图片描述

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

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

办法五:办法四的加强版

思路:把数据处理干净传过去,使用useRef()处理数据

代码:

在这里插入图片描述

完整代码:

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

办法六:办法五的加强版

期望后端接口数据:

在这里插入图片描述

实际后端接口数据:

在这里插入图片描述

代码:

在这里插入图片描述

完整代码:

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

  useEffect(() => https://blog.csdn.net/weixin_45024453/article/details/{
    dispatch(https://blog.csdn.net/weixin_45024453/article/details/{
      type: 'OnboardEdgeModel/getProductList',
    });
  }, []);

  return (
    styles.home_box}>
      <Banner content=https://blog.csdn.net/weixin_45024453/article/details/{onbDate} />
      https://blog.csdn.net/weixin_45024453/article/details/{/*  */}
      <PageTitleThreeC content=https://blog.csdn.net/weixin_45024453/article/details/{infoRef.current} />
      <Content01 content=https://blog.csdn.net/weixin_45024453/article/details/{productLists[0]} />
      <Content02 content=https://blog.csdn.net/weixin_45024453/article/details/{productLists} />
      https://blog.csdn.net/weixin_45024453/article/details/{/*  */}
    
  );
};
export default connect((https://blog.csdn.net/weixin_45024453/article/details/{ OnboardEdgeModel }) => (https://blog.csdn.net/weixin_45024453/article/details/{
  OnboardEdgeModel,
}))(OnboardEdge);

推荐使用:办法三useRef()

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

之前解决了那么多,但useState在项目实际中依然没有解决。

终极简单思路:处理“干净的”数据传给组件,再传递的时候进行一个数组对象的截取react适用,vue没有实践过。

处理前:

在这里插入图片描述

处理后:

在这里插入图片描述

字符串转数组:

期待把后端的数据title字段进行一个split()截取

在这里插入图片描述

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

); }

总结:

大道求简。在写的过程中,一点一点完善,发现到了最后,有更加简单的方法,根本不用走那一套。

你要问我有没有意义,仁者见仁。

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/93d80e1246.html