Установить начальные переменные в Formik из состояния, если оно находится в режиме редактирования

#javascript #reactjs #setstate #formik #yup

#javascript #reactjs #setstate #formik #ага

Вопрос:

Я использую Formik для проверки некоторых данных. Он отлично работает, когда он должен создавать новую сущность, но возникают проблемы, когда я хочу отредактировать сущность.

Режим редактирования должен быть активирован из состояния (this.state.edit === true ), также данные объекта хранятся в состоянии, например this.state.name имеет там строковое значение.

Я помещаю журнал консоли в рендеринг, проблема в том, что журнал печатается несколько раз, в первый раз с пустой строкой this.sate.name и значение this.state.edit равно false. Следующий выводит его правильно, это редактирование true и name, содержащее значение.

Вот код:

 import React from 'react';
import { Redirect } from 'react-router-dom';
import { Formik, Form, Field } from 'formik';
import { Input, Button, Label, Grid } from 'semantic-ui-react';
import { connect } from 'react-redux';
import * as Yup from 'yup';
import { Creators } from '../../../actions';

class CreateCompanyForm extends React.PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      name: '',
      redirectCreate: false,
      redirectEdit: false,
      edit: false,
    };
  }

  componentDidMount() {
    const {
      getCompany,
      getCompanies,
      location: { pathname },
    } = this.props;
    getCompanies({
      name: '',
    });

    if (pathname.substring(11) !== 'create') {
      getCompany(pathname.substring(16));
      this.setState({
        edit: true,
      });

      this.setState({
        name: this.props.company.name,
      });
    }
  }



  handleSubmitCreate = e => {
    e.preventDefault();
    const { createCompany, getCompanies } = this.props;
    createCompany(this.state);
    this.setState({ redirectCreate: true });
    getCompanies(this.props.query);
  };

  handleSubmit = values => {
    const { createCompany, getCompanies } = this.props;
    createCompany(values);
    this.setState({ redirectCreate: true });
    getCompanies(this.props.query);
  };

  handleSubmitEdit = e => {
    e.preventDefault();
    const { name } = this.state;
    const { updateCompany } = this.props;
    updateCompany(this.props.company._id, {
      name,
    });
    this.setState({ redirectEdit: true });
  };

  render() {
    let title = 'Create company';
    let buttonName = 'Create';
    let submit = this.handleSubmitCreate;

    const { redirectCreate, redirectEdit } = this.state;

    if (redirectCreate) {
      return <Redirect to="/companies" />;
    }

    if (redirectEdit) {
      return <Redirect to={`/companies/${this.props.company._id}`} />;
    }

    if (this.state.edit) {
      title = 'Edit company';
      buttonName = 'Edit';
      submit = this.handleSubmitEdit;
    }
    console.log('state: ', this.state); // first time it is empty, next times it has data
    let initialValues = {};
    if (this.state.edit) {
      initialValues = {
        name: this.state.name,
      };
    } else {
      initialValues = {
        name: '',
      };
    }

    const validationSchema = Yup.object({
      name: Yup.string().required('This field is required'),
    });

    return (
      <>
        <Button type="submit" form="amazing">
          create company
        </Button>

        <Formik
          htmlFor="amazing"
          initialValues={initialValues}
          validationSchema={validationSchema}
          onSubmit={values => this.handleSubmit(values)}>
          {({ values, errors, touched, setValues, setFieldValue }) => (
            <Form id="amazing">
              <Grid>
                <Grid.Column>
                  <Label>Company name</Label>
                  <Field name="name" as={Input} placeholder="write a name" />
                  <div>{touched.name amp;amp; errors.name ? errors.name : null}</div>
                </Grid.Column>
              </Grid>

              <Button type="submit" floated="right" form="amazing">
                {buttonName} company
              </Button>
            </Form>
          )}
        </Formik>
      </>
    );
  }
}

const mapStateToProps = state => ({
  companies: state.companies.companies,
  company: state.companies.selectedCompany,
  query: state.companies.query,
});

const mapDispatchToProps = {
  getCompanies: Creators.getCompaniesRequest,
  createCompany: Creators.createCompanyRequest,
  getCompany: Creators.getCompanyRequest,
  updateCompany: Creators.updateCompanyRequest,
};

export default connect(mapStateToProps, mapDispatchToProps)(CreateCompanyForm);
  

Я поместил сюда весь файл, чтобы иметь больше контекста. Это способ установить initialValue name со значением из this.state.name и поместить его в поле ввода?

Ответ №1:

По умолчанию Formik не выполняет повторную визуализацию при изменении начальных значений. Вы можете передать enableReinitialize prop компоненту Formik, чтобы разрешить это.

Как вы сказали в комментарии, при первом рендеринге у него нет данных, следовательно, он инициализирует Formik с пустыми значениями. С этим реквизитом он должен повторно отображаться, если начальные значения изменяются.

https://formik.org/docs/api/formik#enablereinitialize-boolean

Комментарии:

1. Спасибо, все работает нормально и экономит мое время. Я использую этот способ … const formik = useFormik({ initialValues: updateData amp;amp; updateData ? Обновленные данные: начальные значения, onSubmit, validate, validateOnChange: false, enableReinitialize: true, });