【问题标题】:Is initial state based on props always bad in React?基于 props 的初始状态在 React 中总是不好的吗?
【发布时间】:2023-01-13 16:18:23
【问题描述】:

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

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 传递的值时更新此输入值。我不希望用户在发生这种情况时丢失他们的输入。

有多糟糕?

【问题讨论】:

  • 用任何东西初始化 state 都是完全没问题的,props 如果需要的话。反模式正在同步它。
  • @EmileBergeron 我从来没有听说过将状态和道具同步称为反模式。
  • 它通常被视为一种反模式,因为它使状态变得无用,因为 prop 应该按原样使用。在您的情况下,您不必将状态与道具同步,以便用户可以使用输入更新值。
  • 这回答了你的问题了吗? React Hooks: handle multiple inputs
  • 根据您的 cmet,我看到 XY problem,您在其中询问一些潜在的不良做法,但问题应该描述您的情况,minimal reproducible example 提供更多上下文。

标签: javascript reactjs use-state react-props


【解决方案1】:

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

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

【讨论】:

  • 它在我的真实示例中确实有意义,也许我应该提供。单击按钮时更新数据源,该信息源也是初始值。但是输入内容不会立即更新。
  • @RoboRobok 在你的例子中,听起来像 state should be lifted up
  • 我同意@EmileBergeron,你可能需要在父母中控制你的状态。如果您需要一个组件,该组件是带有某些样式或周围其他无状态元素的输入,请使 MyInput 组件接受 valueonChange 的道具并将其传递给它呈现的内部输入
  • 嗯,是的,但在现实生活中,如果你有复杂的用户界面,在父组件中输入的值很快就会变得丑陋。
  • 它不应该太糟糕,如果没有适当的上下文我很难说,也许你的情况有更好的解决方案,但无论如何你在这个例子中所做的对我来说没什么意义
【解决方案2】:

在 React.js 中使用派生状态的问题经常被误解,which this StackOverflow question proves.

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

然而,如果EmailInput组件对initialValue做了一些修改,如果我们遵循"rule of lifting state up"(我相信作者试图解释in this comment),这样的逻辑将不必要地污染父组件。

在这种情况下,我认为如果谨慎使用,反模式可能是一个可以接受的选择。 Robin Wieruch blog post 使用所述反模式的地方。

另一种解决方案是使用 key 属性 (useful in this case),但这仅在密钥和 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>
        </>
    );
}

【讨论】:

    猜你喜欢
    • 2018-09-18
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-28
    • 1970-01-01
    • 2022-01-03
    • 2016-07-14
    相关资源
    最近更新 更多