为啥在反应的“useState”钩子中一遍又一遍地设置初始状态

Posted

技术标签:

【中文标题】为啥在反应的“useState”钩子中一遍又一遍地设置初始状态【英文标题】:Why is initial state being set over and over again in the "useState" hook of react为什么在反应的“useState”钩子中一遍又一遍地设置初始状态 【发布时间】:2021-04-23 10:42:28 【问题描述】:

我创建了一个函数,它正在侦听 resize 事件,它检查窗口宽度并更新我的 IsMobile 变量 if(width

代码如下:

import React,  useEffect, useState  from 'react';

export interface MechnicalLiftProps 


const MechnicalLift: React.SFC<MechnicalLiftProps> = () => 

    const [IsMobile, setIsMobile] = useState(true)

    const handleWindowChange = () => 

        console.log('window inner width', window.innerWidth);
        console.log('is mobile in handle', IsMobile);

        if (window.innerWidth <= 600 && IsMobile === false) 
            setIsMobile(true);
            console.log('is mobile set to true');
        

        if (window.innerWidth > 600 && IsMobile === true) 
            setIsMobile(false);
            console.log('is mobile set to false');
        

    

    useEffect(() => 
        console.log('mount running');
        window.addEventListener('resize', handleWindowChange)
        handleWindowChange()
        return () => 
            window.removeEventListener('resize', handleWindowChange)
        
    , [])

    useEffect(() => 
        console.log('is this mobile ', IsMobile);
    , [IsMobile])

    return (
        <div>

        </div>
    );


export default MechnicalLift;

我的控制台输出:

我觉得每次重新渲染组件时都会设置初始状态,否则为什么每次处理窗口更改时 IsMobile 都设置为 true,即使它多次设置为 false。 Hooks 新手请尽可能详细说明您的解释

【问题讨论】:

【参考方案1】:

由于useEffect 上的空数组,您在第一次渲染时只设置了一次事件侦听器。您创建的函数在第一次渲染中引用了IsMobile,它的值是true。它的价值永远不会改变。

如果需要知道状态的最新值,可以使用set state的回调版本:

const handleWindowChange = () => 
  setIsMobile(prev => 
    console.log('previous value', prev);
    if (window.innerWidth <= 600 && prev === false) 
      return true;
    
    if (window.innerWidth > 600 && prev === true) 
      return false;
    
    return prev;
  );
);

顺便说一句,如果值没有改变,设置状态将不会重新呈现,因此您无需防范将其设置为已有的值。换句话说,如果您不需要日志记录,那么您的代码可以简化为:

const handleWindowChange = () => 
  setIsMobile(window.innerWidth <= 600);

【讨论】:

从我收集的内容来看,如果您将数组保持为空,则使用 E​​ffect 将像 mount 一样运行,并且我想在组件挂载时添加一次事件侦听器并像我在组件中那样删除该事件侦听器将卸载。抱歉,我没有得到参考部分,您可以提供链接或其他内容以供进一步阅读。所以功能组件中的 IsMobile 与基于类的组件中的 this.state.IsMobile 不同。 在函数组件中,你的状态由 local 变量表示。注意IsMobileconst;它永远不会改变。所以获得新状态值的唯一方法是再次渲染并创建一个新的本地const。由于您仅在第一次渲染时创建回调函数,因此该回调函数在其闭包中只有第一个局部变量。有关关闭的更多信息see this link

以上是关于为啥在反应的“useState”钩子中一遍又一遍地设置初始状态的主要内容,如果未能解决你的问题,请参考以下文章

为啥这不会一遍又一遍地返回一个新值?爪哇

为啥我的组件一遍又一遍地重新绘制而没有发生任何变化?

为啥我的 axios 使用 React.useEffect 一遍又一遍地从 Rails 后端获取调用?

Google Cloud Run 一遍又一遍地错误运行

一遍又一遍地运行代码

一遍又一遍地从 AppSettings 中读取整数