避免在React中父组件中的useState之后再次将prop传递给子组件

问题描述 投票:0回答:1

我想避免在 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 值.

我该如何解决这个问题?

谢谢大家的建议。

reactjs react-props
1个回答
0
投票

每次 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 进行初始化,但随后独立管理自己的状态。

© www.soinside.com 2019 - 2024. All rights reserved.