Обновление локального состояния функционального компонента с использованием данных из состояния Redux - PullRequest
1 голос
/ 19 июня 2020

Я строю контакт-менеджер. Когда пользователь нажимает кнопку обновления для указанного c контакта, отправляется действие, и свойство «hotContact» в состоянии редуктора заполняется объектом. Я хочу, чтобы поля ContactForm были заполнены именем и номером «hotContact». Однако, несмотря на то, что hotContact загружается в состояние redux, мой компонент ContactForm не отображает имя и номер hotContact. Как я могу продолжить? Это то, что у меня есть до сих пор.

Я попытался вызвать setFormData в условном блоке, чтобы проверить, присутствует ли hotContact, а loadHotContact - false, но это просто дает мне бесконечную ошибку повторного рендеринга.

import React, { useState } from 'react';
import { connect } from 'react-redux';
import { addContact, updateContact } from '../actions/contacts';

const ContactForm = ({
  addContact,
  updateContact,
  contacts: { hotContact, loadingHotContact },
}) => {


  const [formData, setFormData] = useState({
    name:
      hotContact === null && loadingHotContact
        ? ''
        : hotContact.name,
    number:
      hotContact === null && loadingHotContact
        ? ''
        : hotContact.number,
  });

  const onFormDataChange = (event) => {
    setFormData({ ...formData, [event.target.name]: event.target.value });
  };

  const { name, number } = formData;

  const handleSubmit = (event) => {
    event.preventDefault();
    const newContact = { name, number };
    addContact(newContact);
    console.log('Submit the form!');
    setFormData({ name: '', number: '' });
  };

  const handleUpdateSubmit = (event) => {
    event.preventDefault();
    const updatedContact = { name, number };
    updateContact(hotContact._id, updatedContact);
  };


  return !hotContact ? (
    <form onSubmit={handleSubmit}>
      <div>
        Name{' '}
        <input
          type='text'
          name='name'
          value={name}
          onChange={(event) => onFormDataChange(event)}
        />
      </div>
      <div>
        Number{' '}
        <input
          type='text'
          name='number'
          value={number}
          onChange={(event) => onFormDataChange(event)}
        />
      </div>
      <input type='submit' value='Add Contact' />
    </form>
  ) : (
    <form onSubmit={handleUpdateSubmit}>
      <div>
        Name{' '}
        <input
          type='text'
          name='name'
          value={name}
          onChange={(event) => onFormDataChange(event)}
        />
      </div>
      <div>
        Number{' '}
        <input
          type='text'
          name='number'
          value={number}
          onChange={(event) => onFormDataChange(event)}
        />
      </div>
      <input type='submit' value='Apply Changes' />
    </form>
  );
};

const mapStateToProps = (state) => ({
  contacts: state.contacts,
});
export default connect(mapStateToProps, { addContact, updateContact })(
  ContactForm
);

1 Ответ

1 голос
/ 19 июня 2020

Это не работает, потому что на первом рендерере useState инициализируется hotContact из реквизита, но когда вы получаете новое значение из реквизита, состояние не обновляется (вот как useState крючок работает)

Если вы хотите обновить свое состояние, вы должны использовать useEffect hook:

const ContactForm = ({
  addContact,
  updateContact,
  contacts: { hotContact, loadingHotContact },
}) => {

  const [formData, setFormData] = useState({
    name:
      hotContact === null && loadingHotContact
        ? ''
        : hotContact.name,
    number:
      hotContact === null && loadingHotContact
        ? ''
        : hotContact.number,
  });

  useEffect(() => {
    const {name, number} = props.hotContact;
    setFormData({
      name: name || '',
      number: number || '',
    });
    // execute this
  }, [hotContact]); // when hotContact changes
}

Кроме того, я думаю, вы можете упростить назначение следующим образом:

const {name, number} = props.hotContact;

setFormData({
  name: name || '',
  number: number || '',
});
...