[英]Is initial state based on props always bad in React?
It's a common React knowledge that having state initialized by props is bad if we don't make them in sync. React 的一个常见知识是,如果我们不使它们同步,则由 props 初始化 state 是不好的。 This is considered fine:
这被认为很好:
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)}
/>
</>
);
}
But what if I actually don't want to update the value when initialValue
changes and want to remove the useEffect()
here?但是,如果我实际上不想在
initialValue
更改时更新值并想在此处删除useEffect()
怎么办? Is it strongly against React philosophy?它强烈反对 React 哲学吗? It makes sense in my case, as I actually don't want to update this input value when something else changes the value passed as
initialValue
.这对我来说很有意义,因为我实际上不想在其他东西更改作为
initialValue
传递的值时更新此输入值。 I don't want users to lose their input when that happens.我不希望用户在发生这种情况时丢失他们的输入。
How bad is it?有多糟糕?
In essence, there's nothing wrong with using a prop as the initial value of a state variable, AFAIK.本质上,使用 prop 作为 state 变量 AFAIK 的初始值并没有错。
However, in your example you're doing something that is kind of nonsensical: You are defining a state variable which is initialized with the value of a prop, and then every time the prop updates you update your state with the same value.但是,在您的示例中,您正在做一些荒谬的事情:您正在定义一个 state 变量,该变量使用道具的值进行初始化,然后每次道具更新时,您都会使用相同的值更新您的 state 。 Regardless of whether it's an anti-pattern or not, it makes no sense - just use the prop directly, you're doing extra work for no profit.
不管它是否是反模式,它都没有意义 - 直接使用 prop,你正在做无利可图的额外工作。 If you remove the
useEffect
you'll get a very valid use for a prop as an initial value of a state variable.如果您删除
useEffect
,您将非常有效地使用 prop 作为 state 变量的初始值。
The question of using a derived state in React.js is often misunderstood, which this StackOverflow question proves.在 React.js 中使用派生 state 的问题经常被误解, 这个 StackOverflow 问题证明了这一点。
In the provided code example from the question, it is unclear why a derived state is being used when the initialValue
prop could be used directly.在问题提供的代码示例中,不清楚为什么在可以直接使用
initialValue
道具时使用派生的 state。 For the sake of clarity, using useEffect
for this purpose would be considered an antipattern.为了清楚起见,为此目的使用
useEffect
将被视为反模式。 Instead, you should check for changes yourself, as demonstrated in the React documentation相反,您应该自己检查更改,如React 文档中所示
However, if the EmailInput
component does some modification on the initialValue
, such logic will unnecessarily pollute the parent component, if we followed the"rule of lifting state up" (Which I believe the author attempts to explain in this comment ).但是,如果
EmailInput
组件对initialValue
做了一些修改,如果我们遵循“提升 state 的规则” (我相信作者试图在此评论中解释),这样的逻辑将不必要地污染父组件。
In this case, I would argue that the antipattern may be an acceptable choice if used sparingly.在这种情况下,我认为如果谨慎使用,反模式可能是一个可以接受的选择。 Robin Wieruch blog post where said antipattern is used.
使用上述反模式的Robin Wieruch 博客文章。
An alternative solution is to use the key
attribute ( useful in this case ), but this is only effective if the key and initialValue
are based off different states.另一种解决方案是使用
key
属性( 在这种情况下很有用),但这仅在 key 和initialValue
基于不同状态时才有效。 Otherwise, it may lead to duplicate renderings.否则,可能会导致重复渲染。
Example with the key
attribute具有
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.