Reacting
Reacting

Reputation: 6123

How to manage a React form only with Redux? Without redux-forms

Before asking this I did a Google search and I didn't find any good resource to manage a form only with Redux. All of the examples use redux-forms. It is only one form and I don't want to install that library to use only on one, minimal, small form.

I can't use local state because the user has the option to go to another screen and then be back on the screen which contains the form, so at some point the component could be unmounted and mounted again and I want it to keep its state.

This is the component I have so far and the way I've been working on it:

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

Right now as you may see I am trying to send the value to the store like this:

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

That is for the firstName field, but when I do the same for the middleName field, it obviously cleans the firstName field.

Here is the reducer:

const initialState = {
  startupThirdStepForm: {},
};

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

export default createReducer(initialState, handlers);

And the action:

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

So what can I do to keep the state of the form fields without cleaning the others?

Upvotes: 0

Views: 609

Answers (2)

jtabuloc
jtabuloc

Reputation: 2535

A very quick suggestion is to create a copy of the state. For you to easily identify what field to update you can add name and value inside payload.

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,
    };
  },
}

Upvotes: 0

nebuler
nebuler

Reputation: 1545

Try doing the following for your reducer instead:

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,
            },
        };
    },
}

Upvotes: 1

Related Questions