Reactjs:如何从依赖于子组件状态的父组件中的方法访问子组件的状态 [英] Reactjs: How to access state of child component.from a method in parent component that depends on state of child component

查看:41
本文介绍了Reactjs:如何从依赖于子组件状态的父组件中的方法访问子组件的状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

家长:

function Parent() {const handleCancelEdit = () =>{setCancelEdit(!cancelEdit);//在子组件中定义设置编辑(!编辑);//在子组件中定义...};返回 (<div><子组件fieldName={电子邮件"}值={电子邮件}inputType={文本"}placeHolder={输入电子邮件"}姓名={电子邮件"}on_change={(e)=>setEmail(e.target.value)}on_click={handleUserEmail}/><子组件fieldName={关于"}价值={约}inputType={文本"}placeHolder={请输入有关您自己的一些详细信息"}名称={关于"}on_change={(e)=>setAbout(e.target.value)}on_click={handleUserAbout}/>

);}

子组件:

function ChildComponent({fieldName, value, inputType, placeHolder, name, on_change, on_click}) {const [edit, setEdit] = useState(false);const [cancelEdit, setCancelEdit] = useState(false)const isEdit = 编辑;返回 (<p>{fieldName}: {value === ''?(<跨度><input type={inputType} placeholder={placeHolder}名称={名称} onChange={on_change}/><按钮类型=提交"onClick={on_click}>添加</button></span>) : ( !isEdit ? (<span> {value} <button onClick={e=>setEdit(!edit)}>Edit</button></span>) :(<跨度><输入类型={输入类型}值={值}名称={名称} onChange={on_change}/><按钮类型=提交"onClick={on_click}>保存</button><按钮类型=提交"onClick={handleCancelEdit}>Cancel</button></span>))}</p>);};

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

编辑

根据 Linda Paiste 进行更改后:

即使父子组件中的 onChange 都正确,子组件中的输入字段不起作用!

解决方案

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

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

<预><代码>function ChildComponent({fieldName, value, inputType, placeHolder, name, onChange, onSubmit, isEdit, setEdit}) {返回 (<p>{fieldName}: {value === ''?(<跨度><input type={inputType} placeholder={placeHolder}名称={名称} onChange={onChange}/><按钮类型=提交"onClick={onSubmit}>添加</button></span>) : ( !isEdit ? (<span> {value} <button onClick={() =>setEdit(true)}>Edit</button></span>) :(<跨度><输入类型={输入类型}值={值}名称={名称} onChange={onChange}/><按钮类型=提交"onClick={onSubmit}>Save</button><按钮类型=提交"onClick={() =>setEdit(false)}>取消</button></span>))}</p>);};

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

function Parent() {const [isEditFields, setIsEditFields] = useState({});const handleSetEdit = (name, isEdit) =>{setIsEditFields((prev) => ({...上一个,[名称]:isEdit}));};/* ... */返回 (<div><子组件fieldName={电子邮件"}值={电子邮件}inputType={文本"}placeHolder={输入电子邮件"}姓名={电子邮件"}onChange={(e) =>setEmail(e.target.value)}onSubmit={handleUserEmail}isEdit={isEditFields.email}setEdit={(isEdit) =>handleSetEdit("email", isEdit)}/><子组件fieldName={关于"}价值={约}inputType={文本"}placeHolder={请输入有关您自己的一些详细信息"}名称={关于"}onChange={(e) =>setAbout(e.target.value)}onSubmit={handleUserAbout}isEdit={isEditFields.about}setEdit={(isEdit) =>handleSetEdit("about", isEdit)}/>

);}


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

function Parent() {const [isEditFields, setIsEditFields] = useState({});const [values, setValues] = useState({关于: '',电子邮件: ''});const getProps = (name) =>({名称,值:值[名称],onChange: (e) =>setValues(prev => ({...上一个,[名称]:e.target.value})),isEdit: isEditFields[name],setEdit: (isEdit) =>setIsEditFields(prev => ({...上一个,[名称]:isEdit}))});const handleUserEmail = console.log//占位符const handleUserAbout = console.log//占位符返回 (<div><子组件fieldName={电子邮件"}inputType={文本"}placeHolder={输入电子邮件"}onSubmit={handleUserEmail}{...getProps("email")}/><子组件fieldName={关于"}inputType={文本"}placeHolder={请输入有关您自己的一些详细信息"}onSubmit={handleUserAbout}{...getProps(关于")}/>

);}

I need to access a method handleCancelEdit() defined in parent component. But, the matter here is that every child component will have its own cancelEdit state. Now, what is happening is, if I call handleCancelEdit() from one child component, every other of the same child components is taking the state and updating themselves(the method is not completely defined yet). That's why, I have defined the cancelEdit state in the child component, thinking that it belongs to this child component only.

Now, how do I make the handleCancelEdit() method make changes to the only child component which called it?

The parent:

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>
    );
}

Child component:

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>
    );
};

I hope it could make it understandable that one child component should not make others to update. Now, how do I do it in this scenario?

EDIT

After making changes according to Linda Paiste:

The input field in the child component is not working even though the onChange in both parent and child is correct!

解决方案

It is always more logical to pass state and data down rather than up. If the Parent needs to interact with the edit state then that state should live in the parent. Of course we want independent edit states for each child, so the parent can't just have one boolean. It needs a boolean for each child. I recommend an object keyed by the name property of the field.

In ChildComponent, we move isEdit and setEdit to props. handleCancelEdit is just () => setEdit(false) (does it also need to clear the state set by 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>
    );
};

In Parent, we need to store those isEdit states and also create a setEdit function for each field.

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>
  );
}


You can clean up a lot of repeated code by storing the values as a single state rather than individual useState hooks. Now 5 of the props can be generated automatically just from the name.

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>
  );
}

这篇关于Reactjs:如何从依赖于子组件状态的父组件中的方法访问子组件的状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆