Reactjs:如何访问子组件的状态 component.from 父组件中依赖于子组件状态的方法

Reactjs: How to access state of child component.from a method in parent component that depends on state of child component

我需要访问父组件中定义的方法 handleCancelEdit()。但是,这里的问题是每个子组件都有自己的 cancelEdit 状态。现在,正在发生的事情是,如果我从一个子组件调用 handleCancelEdit(),则所有其他相同的子组件都会获取状态并更新自身(该方法尚未完全定义)。所以,我在子组件中定义了cancelEdit状态,认为它只属于这个子组件。

现在,如何让 handleCancelEdit() 方法对调用它的唯一子组件进行更改?

家长:

function Parent() {
    const handleCancelEdit = () => {
        setCancelEdit(!cancelEdit);  // defined in child component
        setEdit(!edit);       // defined in child component
        ...
    };
    return (
    <div>
        <ChildComponent
            fieldName={"Email"}
            value={email}
            inputType={"text"}
            placeHolder={"Enter email"}
            name={"email"}
            on_change={(e)=>setEmail(e.target.value)}
            on_click={handleUserEmail}
         />
         <ChildComponent
             fieldName={"About"}
             value={about}
             inputType={"text"}
             placeHolder={"Enter some details about yourself"}
             name={"about"}
             on_change={(e)=>setAbout(e.target.value)}
             on_click={handleUserAbout}
         />
    </div>
    );
}

子组件:

function ChildComponent({fieldName, value, inputType, placeHolder, name, on_change, on_click}) {
    const [ edit, setEdit ] = useState(false);
    const [ cancelEdit, setCancelEdit ] = useState(false)
    const isEdit = edit;
    return (
        <p>{fieldName}: {value === ''? (
            <span>
                <input type={inputType} placeholder={placeHolder}
                    name={name}  onChange={on_change}
                />
                <button type="submit" onClick={on_click}>Add</button>
            </span>
            ) : ( !isEdit ? (<span> {value} <button onClick={e=>setEdit(!edit)}>Edit</button></span>) :
            (<span>
                <input type={inputType} value={value}
                        name={name}  onChange={on_change}
                />
                <button type="submit" onClick={on_click}>Save</button>
                <button type="submit" onClick={handleCancelEdit}>Cancel</button>
            </span>)                            
            )}
        </p>
    );
};

我希望它能让人们理解一个子组件不应该让其他组件更新。现在,在这种情况下我该怎么做?

编辑

根据 Linda Paiste 进行更改后:

尽管父组件和子组件中的 onChange 都正确,但子组件中的输入字段不起作用!

向下传递状态和数据总是比向上传递更符合逻辑。如果 Parent 需要与 edit 状态交互,那么该状态应该存在于 parent 中。当然我们希望每个 child 都有独立的 edit 状态,所以 parent 不能只有一个 boolean。每个 child 需要一个 boolean。我推荐一个 object 由字段的 name 属性 键控。

ChildComponent中,我们将isEditsetEdit移动到props。 handleCancelEdit就是() => setEdit(false)(是不是也需要清除onChange设置的状态?)


function ChildComponent({fieldName, value, inputType, placeHolder, name, onChange, onSubmit, isEdit, setEdit}) {
    return (
        <p>{fieldName}: {value === ''? (
            <span>
                <input type={inputType} placeholder={placeHolder}
                    name={name}  onChange={onChange}
                />
                <button type="submit" onClick={onSubmit}>Add</button>
            </span>
            ) : ( !isEdit ? (<span> {value} <button onClick={() =>setEdit(true)}>Edit</button></span>) :
            (<span>
                <input type={inputType} value={value}
                        name={name}  onChange={onChange}
                />
                <button type="submit" onClick={onSubmit}>Save</button>
                <button type="submit" onClick={() => setEdit(false)}>Cancel</button>
            </span>)                            
            )}
        </p>
    );
};

Parent中,我们需要存储那些isEdit状态,并为每个字段创建一个setEdit函数。

function Parent() {
  const [isEditFields, setIsEditFields] = useState({});

  const handleSetEdit = (name, isEdit) => {
    setIsEditFields((prev) => ({
      ...prev,
      [name]: isEdit
    }));
  };

  /* ... */

  return (
    <div>
      <ChildComponent
        fieldName={"Email"}
        value={email}
        inputType={"text"}
        placeHolder={"Enter email"}
        name={"email"}
        onChange={(e) => setEmail(e.target.value)}
        onSubmit={handleUserEmail}
        isEdit={isEditFields.email}
        setEdit={(isEdit) => handleSetEdit("email", isEdit)}
      />
      <ChildComponent
        fieldName={"About"}
        value={about}
        inputType={"text"}
        placeHolder={"Enter some details about yourself"}
        name={"about"}
        onChange={(e) => setAbout(e.target.value)}
        onSubmit={handleUserAbout}
        isEdit={isEditFields.about}
        setEdit={(isEdit) => handleSetEdit("about", isEdit)}
      />
    </div>
  );
}

您可以通过将 values 存储为单个状态而不是单独的 useState 挂钩来清理大量重复代码。现在可以从 name.

自动生成 5 个道具
function Parent() {
  const [isEditFields, setIsEditFields] = useState({});

  const [values, setValues] = useState({
      about: '',
      email: ''
  });

  const getProps = (name) => ({
      name,
      value: values[name],
      onChange: (e) => setValues(prev => ({
          ...prev,
          [name]: e.target.value
      })),
      isEdit: isEditFields[name],
      setEdit: (isEdit) => setIsEditFields(prev => ({
          ...prev,
          [name]: isEdit
      }))
  });

  const handleUserEmail = console.log // placeholder
  const handleUserAbout = console.log // placeholder

  return (
    <div>
      <ChildComponent
        fieldName={"Email"}
        inputType={"text"}
        placeHolder={"Enter email"}
        onSubmit={handleUserEmail}
        {...getProps("email")}
      />
      <ChildComponent
        fieldName={"About"}
        inputType={"text"}
        placeHolder={"Enter some details about yourself"}
        onSubmit={handleUserAbout}
        {...getProps("about")}
      />
    </div>
  );
}