繁体   English   中英

基于道具的初始 state 在 React 中总是不好的吗?

[英]Is initial state based on props always bad in React?

React 的一个常见知识是,如果我们不使它们同步,则由 props 初始化 state 是不好的。 这被认为很好:

import { useState, useEffect } from 'react';

export default function MyInput({ initialValue }) {
    const [value, setValue] = useState(initialValue);

    useEffect(
        () => setValue(initialValue),
        [initialValue]
    );

    return (
        <>
            <h1>The value is {value}</h1>
            <input
                type="text"
                value={value}
                onChange={event => setValue(event.target.value)}
            />
        </>
    );
}

但是,如果我实际上不想在initialValue更改时更新值并想在此处删除useEffect()怎么办? 它强烈反对 React 哲学吗? 这对我来说很有意义,因为我实际上不想在其他东西更改作为initialValue传递的值时更新此输入值。 我不希望用户在发生这种情况时丢失他们的输入。

有多糟糕?

本质上,使用 prop 作为 state 变量 AFAIK 的初始值并没有错。

但是,在您的示例中,您正在做一些荒谬的事情:您正在定义一个 state 变量,该变量使用道具的值进行初始化,然后每次道具更新时,您都会使用相同的值更新您的 state 。 不管它是否是反模式,它都没有意义 - 直接使用 prop,你正在做无利可图的额外工作。 如果您删除useEffect ,您将非常有效地使用 prop 作为 state 变量的初始值。

在 React.js 中使用派生 state 的问题经常被误解, 这个 StackOverflow 问题证明了这一点。

在问题提供的代码示例中,不清楚为什么在可以直接使用initialValue道具时使用派生的 state。 为了清楚起见,为此目的使用useEffect将被视为反模式。 相反,您应该自己检查更改,如React 文档中所示

但是,如果EmailInput组件对initialValue做了一些修改,如果我们遵循“提升 state 的规则” (我相信作者试图在此评论中解释),这样的逻辑将不必要地污染父组件。

在这种情况下,我认为如果谨慎使用,反模式可能是一个可以接受的选择。 使用上述反模式的Robin Wieruch 博客文章

另一种解决方案是使用key属性( 在这种情况下很有用),但这仅在 key 和initialValue基于不同状态时才有效。 否则,可能会导致重复渲染。

具有key属性的示例

// EmailInput.jsx
export default function EmailInput({ initialValue, onChange }) {
    const [value, setValue] = useState(initialValue);

    const handleChange = (event) => {
        const newValue = event.target.value;
        // do some modification on the newValue
        setValue(newValue);
        onChange(newValue); // pass value to parent
    };

    return (
        <>
            <h1>The Email is {value}</h1>
            <input type="text" value={value} onChange={handleChange} />
        </>
    );
}
// Checkout.jsx
export function Checkout() {
    const [user, setUser] = useState({
        id: 1,
        email: "example@example.com",
    });
    return (
        <>
            <EmailInput
                initialValue={user.email}
                key={user.id}
                onChange={(value) => setUser({ id: user.id, email: value })}
            />
            <button
                onClick={() => setUser({id: 2, email: "foo@bar.com"})}
            >
                Update user
            </button>
        </>
    );
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM