来自 react useState 的状态在使用键 属性 时更新,但需要 useEffect 或类似方法才能更新
State from react useState is updated when key property is used but requires useEffect or similar method to update otherwise
我有以下组件:
import React, { useState } from "react";
import { FormControl, TextField } from "@material-ui/core";
interface IProps {
text?: string;
id: number;
onValueChange: (text: string, id: number) => void;
placeholder: string;
}
export const QuestionTextRow: React.FC<IProps> = (props) => {
const [item, onItemChange] = useState(props.text);
const onChange = (e: React.FormEvent<HTMLInputElement>) => {
const newValue = e.currentTarget.value;
onItemChange(newValue);
props.onValueChange(newValue, props.id);
};
return (
<>
<FormControl fullWidth>
<div>{props.text}</div>
<TextField
aria-label="question-text-row"
onDragStart={(e) => {
e.preventDefault();
e.stopPropagation();
}}
value={item}
onChange={(ev: React.ChangeEvent<HTMLInputElement>): void => {
onChange(ev);
}}
/>
</FormControl>
</>
);
};
它是通过以下组件呈现的:
const renderQuestionOptions = (id: number): JSX.Element => {
const item = props.bases.find((x) => x.sortableId === id);
if (!item) return <> </>;
return (
<div className={classes.questionPremiseRow}>
<div className={classes.rowOutline}>
<QuestionOptionsSortableRow item={item} isDisabled={false} onClickRow={onClickBasisRow}>
<QuestionTextRow
text={item.text ? item.text.text : ""}
id={item.sortableId}
onValueChange={basisValueChanged}
placeholder={intl.formatMessage({ id: "question.create.basis.row.placeholder" })}
></QuestionTextRow>
</QuestionOptionsSortableRow>
</div>
</div>
);
};
它呈现以下列表:
如您所见,props.text
中的 props.text
和 useState
item
呈现相同。如果 props.text
更新,它不会反映在 useState
上。
我可以通过 useEffect
解决它以使其工作:
useEffect(() => {
onItemChange(props.text);
}, [props.text]);
https://reactjs.org/docs/hooks-effect.html
但是,如果我将 key={`${item.text?.text}-${item.sortableId}`}
添加到 QuestionTextRow
,它会在不使用 useEffect
的情况下工作。怎么会?
我知道应该使用静态唯一键,但如果使用 key={item.uniqueId}
会不会得到相同的结果?
https://www.npmjs.com/package/react-key-index
The argument passed to useState is the initial state much like setting
state in constructor for a class component and isn't used to update
the state on re-render
However If I add key={${item.text?.text}-${item.sortableId}
} to
QuestionTextRow it will work without using useEffect. How come?
那是因为reconciliation。在反应中,当你在一个渲染上说:
<SomeComponent key={1}/>
如果在下一次渲染中使用不同的键渲染同一个组件(在同一个地方),比如:
<SomeComponent key={2}/>
React 将销毁与前一个组件相关的实例并为此组件创建一个新实例,因此该组件内的 useState
将再次使用提供的 text
属性 进行初始化(就像您第一次创建组件时一样)。
如果上一次和下一次渲染中的某个组件的密钥相同,而您只是更改了一些其他道具,在这种情况下,组件将被重新渲染(没有实例被破坏),这就是为什么您没有看到 text
属性反映在状态中。
有时像 useEffect
解决方案中那样将 props 复制到 state 可能会很棘手,我建议您阅读这篇 post,它是关于 类 但同样的想法适用.
我有以下组件:
import React, { useState } from "react";
import { FormControl, TextField } from "@material-ui/core";
interface IProps {
text?: string;
id: number;
onValueChange: (text: string, id: number) => void;
placeholder: string;
}
export const QuestionTextRow: React.FC<IProps> = (props) => {
const [item, onItemChange] = useState(props.text);
const onChange = (e: React.FormEvent<HTMLInputElement>) => {
const newValue = e.currentTarget.value;
onItemChange(newValue);
props.onValueChange(newValue, props.id);
};
return (
<>
<FormControl fullWidth>
<div>{props.text}</div>
<TextField
aria-label="question-text-row"
onDragStart={(e) => {
e.preventDefault();
e.stopPropagation();
}}
value={item}
onChange={(ev: React.ChangeEvent<HTMLInputElement>): void => {
onChange(ev);
}}
/>
</FormControl>
</>
);
};
它是通过以下组件呈现的:
const renderQuestionOptions = (id: number): JSX.Element => {
const item = props.bases.find((x) => x.sortableId === id);
if (!item) return <> </>;
return (
<div className={classes.questionPremiseRow}>
<div className={classes.rowOutline}>
<QuestionOptionsSortableRow item={item} isDisabled={false} onClickRow={onClickBasisRow}>
<QuestionTextRow
text={item.text ? item.text.text : ""}
id={item.sortableId}
onValueChange={basisValueChanged}
placeholder={intl.formatMessage({ id: "question.create.basis.row.placeholder" })}
></QuestionTextRow>
</QuestionOptionsSortableRow>
</div>
</div>
);
};
它呈现以下列表:
如您所见,props.text
中的 props.text
和 useState
item
呈现相同。如果 props.text
更新,它不会反映在 useState
上。
我可以通过 useEffect
解决它以使其工作:
useEffect(() => {
onItemChange(props.text);
}, [props.text]);
https://reactjs.org/docs/hooks-effect.html
但是,如果我将 key={`${item.text?.text}-${item.sortableId}`}
添加到 QuestionTextRow
,它会在不使用 useEffect
的情况下工作。怎么会?
我知道应该使用静态唯一键,但如果使用 key={item.uniqueId}
会不会得到相同的结果?
https://www.npmjs.com/package/react-key-index
The argument passed to useState is the initial state much like setting state in constructor for a class component and isn't used to update the state on re-render
However If I add key={
${item.text?.text}-${item.sortableId}
} to QuestionTextRow it will work without using useEffect. How come?
那是因为reconciliation。在反应中,当你在一个渲染上说:
<SomeComponent key={1}/>
如果在下一次渲染中使用不同的键渲染同一个组件(在同一个地方),比如:
<SomeComponent key={2}/>
React 将销毁与前一个组件相关的实例并为此组件创建一个新实例,因此该组件内的 useState
将再次使用提供的 text
属性 进行初始化(就像您第一次创建组件时一样)。
如果上一次和下一次渲染中的某个组件的密钥相同,而您只是更改了一些其他道具,在这种情况下,组件将被重新渲染(没有实例被破坏),这就是为什么您没有看到 text
属性反映在状态中。
有时像 useEffect
解决方案中那样将 props 复制到 state 可能会很棘手,我建议您阅读这篇 post,它是关于 类 但同样的想法适用.