Naser
Naser

Reputation: 43

redux-form getFormState side-effects

I have many forms in my app. I created a single form reducer for each of them under its parent reducer and combined them. For fetching theirs data I am using getFormState, Everything is okay in fetching form states side, but in redux state active form duplicated in all redux-form reducers!!! Each redux-form action apply to all forms.

redux-form in redux-dev-tools screenshot

I don't know how I can share all code with you that I can present whole situation. but I try share some code btw here:

This is my signup form:

SigninForm = reduxForm({
  form: 'signin',
  validate,
  getFormState: ({ auth }) => auth.signin.form
})(SigninForm)

sign up reducer

import { combineReducers } from 'redux'
import { reducer as reduxFormReducer } from 'redux-form'

const signin = combineReducers({
  error,
  isLogging,
  form: reduxFormReducer
})

export default signin

and Filters form:

export default compose(
  connect(null, { ...actions }),
  reduxForm({
    form: 'filters',
    destroyOnUnmount: false,
    initialValues: {
      pool: 'either',
      open_house: false,
      listing_statuses: {
        ...activeStatuses
      },
      property_subtypes,
      minimum_sold_date: '3', // unit is month but it need to timestamp
      minimum_bedrooms: 'any',
      minimum_bathrooms: 'any',
      minimum_parking_spaces: 'any'
    },
    getFormState: ({ search }) => search.filters.form
  }),
  withHandlers({
    onSubmitHandler: ({ submitFiltersForm }) => values => {
      submitFiltersForm(values)
    }
  })
)(Filters)

and my root reducer:

const appReducer = combineReducers({
  socket,
  user,
  auth,
  brand,
  search,
  routing: routerReducer,
  listing: createNamedWrapperReducer(listing, 'LISTING')
})

export default (state, action) => appReducer(state, action)

P.S: when I use a single form reducer in my root reducer without use getFormState everything working well.

OS: Mac, node: 8.3.0, react: 15.4.2, redux: 3.6.0, redux-form: 7.0.0, browser: 60.0.3112.101 (Official Build) (64-bit)

Upvotes: 2

Views: 2241

Answers (2)

gustavohenke
gustavohenke

Reputation: 41440

This is more of a Redux issue than anything else.

See, in Redux, all reducers receive all actions.
This is an architectural decision that makes it simple to react to weird business ideas.

Therefore, if you're duplicating the redux-form reducer all around your codebase, you're also duplicating the state of all forms, since the actions type is the same for every form.

The getFormState option is not meant to work around multiple instances of the reducer; it's meant to place your redux-form state somewhere else, in case the root-level form key cannot be used.

Therefore, the solution is to do what you say in the question, and use a single form reducer in your entire application.

Upvotes: 0

Patrik Prevuznak
Patrik Prevuznak

Reputation: 2261

From what I understand, you do not use redux-form properly (correct me if I'm wrong).

From getting started:

Form Reducer

It serves for all of your form components, so you only have to pass it once.

Redux-form assumes that there's only one redux-form reducer in your entire application's state. In other words, form reducer shall not be nested.

Remove this

const signin = combineReducers({
  error,
  isLogging,
  form: reduxFormReducer // <-- delete this line
})

and append this

import { reducer as reduxFormReducer } from 'redux-form'
...
const appReducer = combineReducers({
  socket,
  user,
  auth,
  brand,
  search,
  routing: routerReducer,
  listing: createNamedWrapperReducer(listing, 'LISTING'),
  form: reduxFormReducer // <-- that's all there is to it
})

export default (state, action) => appReducer(state, action)

then in your component

SigninForm = reduxForm({
  form: 'signin',
  validate,
  getFormState: ({ form }) => form // <-- you don't need to use this line now
})(SigninForm)

From docs:

getFormState : Function [optional]

A function that takes the entire Redux state and returns the state slice which corresponds to where the redux-form reducer was mounted. This functionality is rarely needed, and defaults to assuming that the reducer is mounted under the form key.

Since we've mounted the formReducer under the form key, no need to have getFormState there at all.

Upvotes: 2

Related Questions