Как управлять реактивной формой только с помощью Redux? Без redux-forms

#javascript #reactjs #ecmascript-6 #redux #react-redux

#javascript #reactjs #ecmascript-6 #redux #react-redux

Вопрос:

Прежде чем задать этот вопрос, я провел поиск в Google и не нашел ни одного хорошего ресурса для управления формой только с помощью Redux. Во всех примерах используются redux-forms. Это только одна форма, и я не хочу устанавливать эту библиотеку для использования только в одной минимальной маленькой форме.

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

Это компонент, который у меня есть до сих пор, и то, как я над ним работал:

 import { compose } from 'redux';
import { connect } from 'react-redux';
import React from 'react';

import FormField from '../FormField/FormField';

import {
  startupThirdStepFormAction,
} from '../../pages/StartupApplication/actions/startupApplicationActions';

const StepThreeForm = ({
  startupThirdStepForm,
  startupThirdStepFormActionHandler,
 }) => (
    <>
      <Container>
        <Row>
          <Col>
            <Form>
              <FormField
                value={startupThirdStepForm.firstName}
                label="First Name"
                controlId="firstName"
                onChange={e =>
                  startupThirdStepFormActionHandler({
                    firstName: e.target.value,
                  })
                }
              />
              <FormField
                value={startupThirdStepForm.middleName}
                label="Middle Name"
                controlId="middleName"
                onChange={e =>
                  startupThirdStepFormActionHandler({
                    middleName: e.target.value,
                  })
                }
              />
            </Form>
          </Col>
        </Row>

      </Container>
    </>
);

export default compose(
  connect(
    store => ({
      startupThirdStepForm: store.startupApplicationReducer.startupThirdStepForm,
    }),
    dispatch => ({
      isStepDoneActionHandler: index => {
        dispatch(isStepDoneAction(index));
      },
      startupThirdStepFormActionHandler: form => {
        dispatch(startupThirdStepFormAction(form));
      },
    }),
  ),
)(StepThreeForm);
  

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

                 onChange={e =>
                  startupThirdStepFormActionHandler({
                    firstName: e.target.value,
                })
  

Это для firstName поля, но когда я делаю то же самое для middleName поля, оно, очевидно, очищает firstName поле.

Вот редуктор:

 const initialState = {
  startupThirdStepForm: {},
};

const handlers = {
  [ActionTypes.STARTUP_THIRD_STEP_FORM](state, action) {
    return {
      ...state,
      startupThirdStepForm: action.payload.startupThirdStepForm,
    };
  },
}

export default createReducer(initialState, handlers);
  

И действие:

 export const startupThirdStepFormAction = startupThirdStepForm => ({
  type: ActionTypes.STARTUP_THIRD_STEP_FORM,
  payload: { startupThirdStepForm },
});
  

Итак, что я могу сделать, чтобы сохранить состояние полей формы без очистки остальных?

Ответ №1:

Вместо этого попробуйте выполнить следующее для вашего редуктора:

 const handlers = {
    [ActionTypes.STARTUP_THIRD_STEP_FORM]: (state, action) {
        return {
            ...state,
            startupThirdStepForm: {
                // to preserve old state
                ...state.startupThirdStepForm,
                // to update with new data
                ...action.payload.startupThirdStepForm,
            },
        };
    },
}
  

Ответ №2:

Очень быстрое предложение — создать копию состояния. Чтобы вы могли легко определить, какое поле нужно обновить, вы можете добавить name и value внутри полезной нагрузки.

 onChange={e =>
           startupThirdStepFormActionHandler({
                    name: "firstName"
                    value: e.target.value,
})


const handlers = {
  [ActionTypes.STARTUP_THIRD_STEP_FORM](state, action) {

    let newStartupThirdStepForm = Object.assign({}, state.startupThirdStepForm);
    newStartupThirdStepForm[action.payload.name] = action.payload.value;

    return {
      ...state,
      startupThirdStepForm: newStartupThirdStepForm,
    };
  },
}