Using React hooks, how can I update an object that is being passed to a child via props?

蹲街弑〆低调 提交于 2020-12-12 05:36:36

问题


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 the input, you can use just one handler function for all the input elements. Inside the function, in this case onInputChange, you can retrieve that information using e.target.name;
  • Notice that I've added an empty array dependecies in your useEffect: without it, the useEffect 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!