Используя перехватчики React, как я могу обновить объект, который передается ребенку через реквизит? - PullRequest
2 голосов
/ 20 марта 2020

Родительский компонент содержит массив объектов. Он сопоставляется с массивом и возвращает дочерний компонент для каждого объекта, заполняя его информацией об этом объекте. Внутри каждого дочернего компонента есть поле ввода, которое, я надеюсь, позволит пользователю обновить объект, но я не могу понять, как это сделать. Между хуками, подпорками и неизменностью объектов я потерян концептуально. Вот упрощенная версия родительского компонента:

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

А вот упрощенная версия дочернего компонента:

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 Ответ

1 голос
/ 20 марта 2020

Возможно, не зная этого, вы подняли состояние : в основном, вместо того, чтобы иметь состояние в компоненте Child, вы сохраняете его в Parent.
Это используется шаблон, и в этом нет ничего плохого: вы просто пропускаете функцию дескриптора, которая позволяет дочерним элементам обновлять состояние Parent: для этого вам нужно реализовать компонент handleChange на Parent, а затем передать это как подпорка для каждого 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} />
    );
}

Несколько вещей, которые вы можете не знать:

  • Используя атрибут name для input, вы можете использовать только одну функцию-обработчик для всех элементов input. Внутри функции, в данном случае onInputChange, вы можете получить эту информацию, используя e.target.name;
  • Обратите внимание, что я добавил пустой массив зависимостей в ваш useEffect: без него, useEffect побежал бы на КАЖДОЙ рендер. Я не думаю, что это то, что вы хотели бы иметь.
    Вместо этого я хотел, чтобы вы хотели выполнить запрос только тогда, когда компонент был смонтирован, и это достижимо с n зависимостями пустых массивов;
...