问题
The parent component contains an array of objects. It maps over the array and returns a child component for every object, populating it with the info of that object. Inside each child component there is an input field that I'm hoping will allow the user to update the object, but I can't figure out how to go about doing that. Between the hooks, props, and object immutability, I'm lost conceptually. Here's a simplified version of the parent component:
const Parent = () => {
const [categories, setCategories] = useState([]);
useEffect(()=>{
// makes an axios call and triggers setCategories() with the response
}
return(
categories.map((element, index) => {
return(
<Child
key = {index}
id = {element.id}
firstName = {element.firstName}
lastName = {element.lastName}
setCategories = {setCategories}
})
)
}
And here's a simplified version of the child component:
const Child = (props) => {
return(
<h1>{props.firstName}</h1>
<input
defaultValue = {props.lastName}
onChange={()=>{
// This is what I need help with.
// I'm a new developer and I don't even know where to start.
// I need this to update the object's lastName property in the parent's array.
}}
)
}
回答1:
Maybe without knowing it, you have lifted the state: basically, instead of having the state in the Child
component, you keep it in the Parent
.
This is an used pattern, and there's nothing wrong: you just miss a handle function that allows the children to update the state of the Parent
: in order to do that, you need to implement a handleChange
on Parent
component, and then pass it as props to every Child
.
Take a look at this code example:
const Parent = () => {
const [categories, setCategories] = useState([]);
useEffect(() => {
// Making your AXIOS request.
}, []);
const handleChange = (index, property, value) => {
const newCategories = [...categories];
newCategories[index][property] = value;
setCategories(newCategories);
}
return categories.map((c, i) => {
return (
<Child
key={i}
categoryIndex={i}
firstName={c.firstName}
lastName={c.lastName}
handleChange={handleChange} />
);
});
}
const Child = (props) => {
...
const onInputChange = (e) => {
props.handleChange(props.categoryIndex, e.target.name, e.target.value);
}
return (
...
<input name={'firstName'} value={props.firstName} onChange={onInputChange} />
<input name={'lastName'} value={props.lastName} onChange={onInputChange} />
);
}
Few things you may not know:
- By using the attribute
name
for theinput
, you can use just one handler function for all theinput
elements. Inside the function, in this caseonInputChange
, you can retrieve that information usinge.target.name
; - Notice that I've added an empty array dependecies in your
useEffect
: without it, theuseEffect
would have run at EVERY render. I don't think that is what you would like to have.
Instead, I guest you wanted to perform the request only when the component was mount, and that is achievable with n empty array dependecies;
来源:https://stackoverflow.com/questions/60766094/using-react-hooks-how-can-i-update-an-object-that-is-being-passed-to-a-child-vi