1

I wrote this code to create Redux store:

import {combineReducers} from 'redux-immutable'

const MyAppReducers = combineReducers({
    Node1: Node1Reducer,
    Node2: Node2Reducer,
    Node3: Node3Reducer,
    Node4: Node4Reducer
})

let store = createStore(
    MyAppReducers,
    composeEnhancers(
        applyMiddleware(
            thunkMiddleware,
            ApiMiddleware,
            loggerMiddleware
        )
    )
)

The result of this configuration is a plain object with inside the Immutable.Map()s:

{
    Node1: Immutable.Map(),
    Node2: Immutable.Map(),
    Node3: Immutable.Map(),
    Node4: Immutable.Map()
}

I want, instead, that all the state tree is an Immutable.Map().

So I tried to pass to combineReducers() directly an Immutable.Map() object:

const MyAppReducers = combineReducers(Immutable.Map({
    Node1: Node1Reducer,
    Node2: Node2Reducer,
    Node3: Node3Reducer,
    Node4: Node4Reducer
}))

But this throws an error in the console:

Uncaught TypeError: reducer is not a function

at combineReducers.js:39

at Array.forEach ()

at combineReducers.js:36

at Map.withMutations (immutable.js:1353)

at combineReducers.js:35

at computeNextEntry (:2:27469)

at recomputeStates (:2:27769)

at :2:31382

at dispatch (createStore.js:165)

at createStore (createStore.js:240)

The documentation of redux-immutable states that I should pass the initialState as a second argument of the createStore function, but my second argument is currently the composeEnhancers function that I need to configure middlewares and other things.

How can I make the entire state tree be an Immutable.Map() object?

Aerendir
  • 6,152
  • 9
  • 55
  • 108

2 Answers2

2

The built-in combineReducers function expects that the state it sees is a plain Javascript object.

If you want the state tree to be an Immutable.js Map instead, you need to use a different function, like the one provided by redux-immutable or other Redux/immutable interop libs.

Note that the Redux createStore function can either be called as:

createStore(rootReducer, initialState, composedEnhancers);
createStore(rootReducer, composedEnhancers);

So, pass your initial Immutable.js Map as the second argument.

Aerendir
  • 6,152
  • 9
  • 55
  • 108
markerikson
  • 63,178
  • 10
  • 141
  • 157
  • Apologies, missed that. Updated my answer. – markerikson Jan 03 '18 at 21:53
  • I've tried to pass the initial state to `createStore` but it causes anyway an error about unknown properties: Unexpected property "StateRoot" found in previous state received by the reducer. Expected to find one of the known reducer property names instead: "size", "_root", "__ownerID", "__hash", "__altered". Unexpected properties will be ignored. And anyway there is the error "Uncaught TypeError: reducer is not a function". Please, can you expand your answer providing me with some more code as I'm not abe to fix with the current suggestions? – Aerendir Jan 04 '18 at 11:20
0

Just for someone who may have the same problem, the full solution is this:

import {combineReducers} from 'redux-immutable'
import {fromJS} from 'immutable'
import { createStore, applyMiddleware } from 'redux';
import ThunkMiddleware from 'redux-thunk'
import {createLogger} from 'redux-logger'

const MyAppInitialState = fromJS({
    Node1: {
        entities: {},
        ui: {}
    },
    Node2: {
        entities: {},
        ui: {}
    },
    Node3: {
        entities: {},
        ui: {}
    },
    Node4: {
        entities: {},
        ui: {}
    }
})

const MyAppReducers = combineReducers({
    Node1: Node1Reducer,
    Node2: Node2Reducer,
    Node3: Node3Reducer,
    Node4: Node4Reducer
})

const LoggerMiddleware = createLogger()

const store = createStore(
    MyAppReducers,
    MyAppInitialState,
    composeEnhancers(
        applyMiddleware(
            thunkMiddleware,
            ApiMiddleware,
            loggerMiddleware
        )
    )
)

// Example of a reducer (just for completeness)
const Node1Reducer = (state = fromJS({entities: {}, ui: {}}), action) => {
    switch (action.type) {
        ...
        default:
            return state
    }
}

With this configuration I'm now able to use Immutable.js with Redux having the entire state as an Immutable tree.

Aerendir
  • 6,152
  • 9
  • 55
  • 108