使用 React 钩子,如何更新通过道具传递给孩子的对象?

squ*_*ers 2 arrays object parent-child reactjs react-hooks

父组件包含一组对象。它映射数组并为每个对象返回一个子组件,用该对象的信息填充它。在每个子组件内都有一个输入字段,我希望它允许用户更新对象,但我不知道如何去做。在钩子、道具和对象不变性之间,我在概念上迷失了。这是父组件的简化版本:

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}
    })
  )
}
Run Code Online (Sandbox Code Playgroud)

这是子组件的简化版本:

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.
      }}
  )
}
Run Code Online (Sandbox Code Playgroud)

Jol*_*lly 5

也许在不知情的情况下,您已经解除了状态:基本上,不是在Child组件中拥有状态,而是将其保存在Parent.
这是一个使用过的模式,并没有错:您只是错过了一个句柄函数,该函数允许子级更新 : 的状态,Parent为此,您需要实现一个handleChangeonParent组件,然后将其作为 props 传递给每个Child.

看看这个代码示例:

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} />
    );
}
Run Code Online (Sandbox Code Playgroud)

你可能不知道的几件事:

  • 通过使用属性nameinput,你可以只使用一个处理函数的所有input元素。在函数内部,在这种情况下onInputChange,您可以使用e.target.name;
  • 请注意,我在您的useEffect: 中添加了一个空数组依赖项,如果没有它,useEffect它将在每次渲染时运行。我不认为那是你想要的。
    取而代之的是,您希望仅在安装组件时执行请求,并且可以使用 n 个空数组依赖项来实现;

  • 您真的花了很多时间来给我一个简单、简洁、充分的答案来回答我的问题。我无法告诉你我是多么感激你这样做。太感谢了!刚刚将其添加到我的代码中并且它起作用了。更重要的是:我明白它为何有效。再次感谢! (3认同)