I'm attemtping to use react-redux-form to manage my forms but am having issues working out how to inject it into the store when I setup my other reducers.
My store is created as follows
import { createStore, applyMiddleware, compose } from 'redux'
import { browserHistory } from 'react-router'
import { routerMiddleware } from 'react-router-redux'
import { makeRootReducer } from '../reducer'
const makeStore = (initialState = {}) => {
const middleware = [
routerMiddleware(browserHistory)
// other middlewares
]
const store = createStore(
makeRootReducer(),
initialState,
compose(
applyMiddleware(...middleware)
)
)
store.asyncReducers = {}
return store
}
module.exports = makeStore
My root reducer
is as follows
import { combineReducers } from 'redux'
import { routerReducer } from 'react-router-redux'
import { combineForms } from 'react-redux-form'
import { initialLoginState } from './components/forms/login'
const makeRootReducer = (asyncReducers) => {
const customReducers = {
// other of my own imported reducers
}
const forms = {
login: initialLoginState
}
const allReducers = {
...customReducers,
forms: combineForms(forms, 'forms'),
routing: routerReducer,
...asyncReducers
}
return combineReducers(allReducers)
}
// mutate the store just this once.
const injectReducer = (store, { key, reducer }) => {
store.asyncReducers[key] = reducer // eslint-disable-line no-param-reassign
store.replaceReducer(makeRootReducer(store.asyncReducers))
}
module.exports = {
makeRootReducer,
injectReducer
}
and my form is like this
<Form model='forms.login' onSubmit={login => console.debug(login)}>
<label>Email</label>
<Control.text model='.username' />
<label>Password</label>
<Control type='password' model='.password' />
<button type="submit">Login</button>
</Form>
When I fire up my app and inspect the state I see the forms sitting in the state as follows:
state:
forms:
login:
username: ''
password: ''
forms:
$form:
focus: false
# ... etc
login:
$form:
focus: false
# ... etc
username: ''
password: ''
And the form behaves as expected.
If I change allreducers
remove the second 'forms'
param, so it looks like this:
const allReducers = {
...customReducers,
forms: combineForms(forms),
routing: routerReducer,
...asyncReducers
}
My state looks the same
state:
forms:
login:
username: ''
password: ''
forms:
$form:
focus: false
# ... etc
login:
$form:
focus: false
# ... etc
username: ''
password: ''
but the form itself no longer works.
What I actually want is a state
that looks like
state:
forms:
login:
$form:
focus: false
# ... etc
username: ''
password: ''
without all the weird nested duplication.
Ultimately in my form Component I need to be able to access the form's errors
object and I'd rather not have to dig into state.forms.forms.login.$form.errors
as that just seems broken to me when I ought to be able to look in state.forms.login.$form.errors
.
How ought I inject combinedForms
into my combinedReducer
along with the other reducers?
In the example you have given, state.forms.login
will contain the model values.
state.forms.forms.login
will contain the react-redux-form
specific information about the form/field state.
This is the expected functionality of react-redux-form
. Your confusion may have stemmed from using 'forms'
as the model name for your combined forms.