React Controlled Form с дочерним/родительским компонентом

Я создаю контролируемую форму с динамическими полями. Компонент Parent получает данные из хранилища избыточности, а затем устанавливает состояние со значениями. Я не хочу делать это со слишком большим количеством строк кода, поэтому я превращаю динамические поля в компонент. Состояния остаются в родительском компоненте, и я использую свойства для передачи функции смены дескриптора.

Родитель:

function EditAbout(props) {
  const [img, setImg] = useState("");
  const [body, setBody] = useState(props.about.body);
  const [instagram, setInstagram] = useState(props.about.links.instagram);
  const [linkedin, setLinkedIn] = useState(props.about.links.linkedin);
  const [press, setPress] = useState(props.about.press)

  const handleSubmit = (e) => {
   // Submit the change to redux
  };

// set states with redux store
  useEffect(() => {
    setBody(props.about.body);
    setInstagram(props.about.links.instagram);
    setLinkedIn(props.about.links.linkedin);
    setPress(props.about.press);
  }, []);

  const handleChangeEventChild = (e, index) =>  {
    e.preventDefault();
    let articles = press
    const {value, name } = e.target
    if (name === "title") {
      articles[index].title = value;
    } else {
      articles[index].link = value;
    }
    setPress(articles)
    console.info(articles[index])
  }

  return (
    <Box>
      <h1>CHANGE ABOUT ME</h1>
      <Input
        label = "Image"
        name = "img"
        type = "file"
        variant = "outlined"
        margin = "normal"
        onChange = {(e) => setImg(e.target.files)}
      />
      <Input
        label = "body"
        value = {body}
        name = "body"
        onChange = {(e) => setBody(e.target.value)}
        variant = "outlined"
        multiline
        rowsMax = {12}
        margin = "normal"
      />
      <Input
        label = "instagram"
        value = {instagram}
        name = "instagram"
        variant = "outlined"
        margin = "normal"
        onChange = {(e) => setInstagram(e.target.value)}
      />
      <Input
        label = "Linkedin"
        value = {linkedin}
        name = "linkedin"
        variant = "outlined"
        margin = "normal"
        onChange = {(e) => setLinkedIn(e.target.value)}
      />
      <Child press = {press} onChange = {handleChangeEventChild} />
      {props.loading ? (
        <CircularProgress color = "black" />
      ) : (
        <Button onClick = {handleSubmit} variant = "contained">
          Send
        </Button>
      )}
    </Box>
  );
}

Ребенок :

function Child(props) {
  const { press, onChange } = props;

  const inputsMarkup = () =>
    press.map((article, index) => (
      <div key = {`press${index}`} style = {{ display: "flex" }}>
        <input
          name = "title"
          value = {press[index].title}
          onChange = {(e) => onChange(e, index)}
        />
        <input
          name = "link"
          value = {press[index].link}
          onChange = {(e) => onChange(e, index)}
        />
        <button>Delete</button>
      </div>
    ));

  return (
    <div>
      <h1>Press :</h1>
      {inputsMarkup()}
    </div>
  );
}

Все в порядке, когда я печатаю родительские входы. Но когда я использую обновление состояния дочерних полей для одного символа, но сразу после этого возвращаюсь к предыдущему состоянию. Также не отображается смена персонажа. Я вижу это только в консоли. Заранее спасибо за помощь

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
983
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что вы изменяете состояние напрямую. Когда вы создаете переменную articles (let articles = press), вы на самом деле не создаете копию, а articles фактически не содержит значения. Это всего лишь ссылка на это значение, которое указывает на расположение объекта в памяти.

Поэтому, когда вы обновляете articles[index].title в своей handleChangeEventChild функции, вы фактически также меняете состояние press. Вы можете подумать, что это нормально, но без вызова setPress() React не узнает об изменении. Итак, хотя значение состояния изменено, вы его не увидите, потому что React не будет его повторно отображать.

Вам нужно создать копию массива press с помощью .map() и создать копию обновленного элемента массива. Вы можете найти обновленный handleChangeEventChild() ниже:

const handleChangeEventChild = (e, index) => {
  e.preventDefault();

  const { value, name } = e.target;

  setPress(
    // .map() returns a new array
    press.map((item, i) => {
      // if the current item is not the one we need to update, just return it
      if (i !== index) {
        return item;
      }

      // create a new object by copying the item
      const updatedItem = {
        ...item,
      };

      // we can safely update the properties now it won't affect the state
      if (name === 'title') {
        updatedItem.title = value;
      } else {
        updatedItem.link = value;
      }

      return updatedItem;
    }),
  );
};

Большое спасибо за ваш ответ. Это сработало, и теперь я понимаю все, что я сделал неправильно.

Bibi 10.12.2020 00:59

Другие вопросы по теме