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
中,我们将isEdit
和setEdit
移动到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>
);
}
我需要访问父组件中定义的方法 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
中,我们将isEdit
和setEdit
移动到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
.
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>
);
}