我想避免在 React 的父组件中的 useState 之后再次将 props 传递给子组件。
让我用下面的例子更好地解释一下
父组件:
export default function ParentComponent() {
const [isDirty, setIsDirty] = useState(false);
const [defaultValue, setDefaultValue] = useState('');
const myInputFieldConfiguration = {
field: 'myfield1',
type: 'text',
isDisabled: false,
value: defaultValue
};
useEffect(() => {
getDefaultData()
}, []);
const getDefaultData = async () => {
const defaultDataResponse = await api.getDefaultData();
setDefaultValue(defaultValueDataResponse);
}
return (
<>
<ChildComponent
inputFieldConfiguration={myInputFieldConfiguration}
onIsDirty={isDirty => setIsDirty(isDirty)}
/>
<>
)
}
子组件:
export default function ChildComponent(props) {
function handleChange(event) {
if(event.target.value !== props.inputFieldConfiguration.value) {
props.onIsDirty(true);
}
}
return (
<>
<input
type={props.inputFieldConfiguration.type}
disabled={props.inputFieldConfiguration.disabled}
value={props.inputFieldConfiguration.value}
onChange={handleChange}
/>
<>
)
}
在上面的示例中,我调用 api 来获取默认值,我在状态中设置此值,然后声明一个变量 myInputFieldConfiguration 将该默认值保留在 value 属性中。然后,我将值 myInputFieldConfiguration 作为 prop 传递给 ChildComponent,并在该组件内使用它来预填充和配置输入字段。 在 ChildComponent 中,当我编辑该输入字段的值时,我调用 onIsDirtyMethod,该方法在 ParentComponent 中设置 isDirtyState。 问题就在那里,当设置状态时,ParentComponent 重新渲染自身并再次将原始 myInputFieldConfiguration 作为 props 传递给 ChildComponent,结果是 ChildComponent 中的输入字段值再次更改为默认的 myInputFieldConfiguration.value 值.
我该如何解决这个问题?
谢谢大家的建议。
每次 ParentComponent 重新渲染时(例如,当 isDirty 状态更改时),它都会将相同的 inputFieldConfiguration 对象传递给 ChildComponent。由于此配置对象包含 defaultValue(在初始 API 调用后未更改),因此 ChildComponent 始终接收初始 defaultValue,从而覆盖对输入字段所做的任何更改。
这种行为是 React 中单向数据流的直接结果。 ChildComponent 没有自己的状态来管理输入值;它完全依赖于从 ParentComponent 传递的 props。因此,ParentComponent 的任何重新渲染都会有效地将 ChildComponent 中的输入字段的值重置为初始默认值。
要解决此问题,ChildComponent 需要管理其自己的输入字段值状态。
export default function ParentComponent() {
const [isDirty, setIsDirty] = useState(false);
const [defaultValue, setDefaultValue] = useState('');
useEffect(() => {
getDefaultData();
}, []);
const getDefaultData = async () => {
const defaultDataResponse = await api.getDefaultData();
setDefaultValue(defaultDataResponse); // Make sure this variable name is correct
}
return (
<>
<ChildComponent
defaultValue={defaultValue}
onIsDirty={setIsDirty}
/>
</>
)
}
export default function ChildComponent(props) {
const [inputValue, setInputValue] = useState(props.defaultValue);
//ensures that if the defaultValue prop changes,
// it updates its internal state. This handles cases where the default
// value might change due to some external factors.
useEffect(() => {
setInputValue(props.defaultValue);
}, [props.defaultValue]);
function handleChange(event) {
const newValue = event.target.value;
if(newValue !== props.defaultValue) {
props.onIsDirty(true);
}
setInputValue(newValue);
}
return (
<>
<input
type="text"
disabled={false}
value={inputValue}
onChange={handleChange}
/>
</>
)
}
ChildComponent 现在有自己的 inputValue 状态。它使用从父级传递的 defaultValue 进行初始化,但随后独立管理自己的状态。