功能性反应如何不重置状态?

Posted

技术标签:

【中文标题】功能性反应如何不重置状态?【英文标题】:How does Functional React Not Reset State? 【发布时间】:2021-01-15 04:53:14 【问题描述】:

我刚刚尝试了 react 功能组件,它似乎很神奇。在我的组件函数中,我都初始化我的状态并返回我的视图。视图中的动作可以调用组件函数范围内定义的函数,从而更新状态。

我的假设是函数组件的函数只被调用一次,但惊讶地发现每次发生状态变化时都会调用它。如果此函数初始化状态,并且在每次状态更改时都被调用,那么我的状态如何不会在每次状态更改时重置?

这是一个键盘记录器组件,它从输入中获取击键并将它们显示在 div 中:

export const KeyLogger = () => 
    const [keysLogged, setKeysLogged] = React.useState<string[]>([]);

    const logKey = (key: string) => 
        setKeysLogged(keysLogged.concat(key));
    

    console.log("HERE");

    return (
        <React.Fragment>
            <input onKeyUp=ev => logKey(ev.key)/>
            <br/>
            <div>keysLogged</div>
        </React.Fragment>
    );
;

当我使用这个组件时,我看到keysLogged 会随着我的输入而增长。

我还看到每次击键都会记录“HERE”。

当我的功能组件的第一行似乎每次调用都初始化keysLogged 时,这怎么可能?

const [keysLogged, setKeysLogged] = React.useState<string[]>([]);

编辑:

使用@Ethan Lipkind 的回复我发现:

每个组件都有一个内部“记忆单元”列表。它们只是 javascript 对象,我们可以在其中放置一些数据。当你调用 useState() 之类的 Hook 时,它会读取当前单元格(或在第一次渲染期间对其进行初始化),然后将指针移动到下一个单元格。这就是多个 useState() 调用各自获取独立本地状态的方式。

所以 react 知道根据 useState 被调用的顺序使用哪个值。而且因为它使用的是useState 而不是createState,所以如果内存单元位置的值已经存在,react 知道不会重新初始化值。

当我在每次调用中切换 keysLoggedAkeysLoggedB 的初始化顺序时,这会产生有趣的影响。

let counter = 0;
export const KeyLogger = () => 
    counter++;

    let keysLoggedA: any;
    let setKeysLoggedA: any;
    let keysLoggedB: any;
    let setKeysLoggedB: any;


    if (counter % 2 === 0) 
        [keysLoggedA, setKeysLoggedA] = React.useState<string[]>([]);
        [keysLoggedB, setKeysLoggedB] = React.useState<string[]>([]);
     else 
        [keysLoggedB, setKeysLoggedB] = React.useState<string[]>([]);
        [keysLoggedA, setKeysLoggedA] = React.useState<string[]>([]);
    


    const logKey = (key: string) => 
        setKeysLoggedA(keysLoggedA.concat(key));
    

    console.log("HERE");

    return (
        <React.Fragment>
            <input onKeyUp=ev => logKey(ev.key)/>
            <br/>
            <div>keysLoggedA</div>
            <div>keysLoggedB</div>
        </React.Fragment>
    );
;

即使我只打电话给setKeysLoggedA,你也可以看到keysLoggedAkeysLoggedB 都得到了更新。

这是因为它完全依赖于 order useState 被调用。这是有道理的,我不知道它还能是什么,但很高兴知道魔法是如何运作的。

【问题讨论】:

【参考方案1】:

每次状态更改时,都会触发重新渲染,这就是您在每次击键时看到日志的原因。由于 useState 钩子在后台工作的方式,不会在每个函数调用上重新初始化状态:https://reactjs.org/docs/hooks-state.html

【讨论】:

对于那些希望在传递的“初始值”更改时重置状态的人,请参阅this thread 和use-state-with-deps package。

以上是关于功能性反应如何不重置状态?的主要内容,如果未能解决你的问题,请参考以下文章

在 ClearTextOnFocus 之后反应原生重置 TextInput

火狐浏览器左上角点击没反应

如何从 props 初始化反应功能组件状态

我们可以在反应中访问无状态组件之外的功能吗?

CloudKit,重新安装应用程序后,如何将我的订阅重置为当前记录状态?

反应:从类转换为具有状态的功能组件