Code Monkey home page Code Monkey logo

redux-immutable's Introduction

redux-immutable

GitSpo Mentions Travis build status NPM version Canonical Code Style

redux-immutable is used to create an equivalent function of Redux combineReducers that works with Immutable.js state.

When Redux createStore reducer is created using redux-immutable then initialState must be an instance of Immutable.Collection.

Problem

When createStore is invoked with initialState that is an instance of Immutable.Collection further invocation of reducer will produce an error:

The initialState argument passed to createStore has unexpected type of "Object". Expected argument to be an object with the following keys: "data"

This is because Redux combineReducers treats state object as a plain JavaScript object.

combineReducers created using redux-immutable uses Immutable.js API to iterate the state.

Usage

Create a store with initialState set to an instance of Immutable.Collection:

import {
  combineReducers
} from 'redux-immutable';

import {
  createStore
} from 'redux';

const initialState = Immutable.Map();
const rootReducer = combineReducers({});
const store = createStore(rootReducer, initialState);

By default, if state is undefined, rootReducer(state, action) is called with state = Immutable.Map(). A different default function can be provided as the second parameter to combineReducers(reducers, getDefaultState), for example:

const StateRecord = Immutable.Record({
	foo: 'bar'
});
const rootReducer = combineReducers({foo: fooReducer}, StateRecord);
// rootReducer now has signature of rootReducer(state = StateRecord(), action)
// state now must always have 'foo' property with 'bar' as its default value

When using Immutable.Record it is possible to delegate default values to child reducers:

const StateRecord = Immutable.Record({
	foo: undefined
});
const rootReducer = combineReducers({foo: fooReducer}, StateRecord);
// state now must always have 'foo' property with its default value returned from fooReducer(undefined, action)

In general, getDefaultState function must return an instance of Immutable.Record or Immutable.Collection that implements get, set and withMutations methods. Such collections are List, Map and OrderedMap.

Using with react-router-redux v4 and under

react-router-redux routeReducer does not work with Immutable.js. You need to use a custom reducer:

import Immutable from 'immutable';
import {
  LOCATION_CHANGE
} from 'react-router-redux';

const initialState = Immutable.fromJS({
  locationBeforeTransitions: null
});

export default (state = initialState, action) => {
  if (action.type === LOCATION_CHANGE) {
    return state.set('locationBeforeTransitions', action.payload);
  }

  return state;
};

Pass a selector to access the payload state and convert it to a JavaScript object via the selectLocationState option on syncHistoryWithStore:

import {
  browserHistory
} from 'react-router';
import {
  syncHistoryWithStore
} from 'react-router-redux';

const history = syncHistoryWithStore(browserHistory, store, {
  selectLocationState (state) {
      return state.get('routing').toJS();
  }
});

The 'routing' path depends on the rootReducer definition. This example assumes that routeReducer is made available under routing property of the rootReducer.

Using with react-router-redux v5

To make react-router-redux v5 work with Immutable.js you only need to use a custom reducer:

import {
  Map
} from 'immutable';
import {
  LOCATION_CHANGE
} from 'react-router-redux';

const initialState = Map({
  location: null,
  action: null
});

export function routerReducer(state = initialState, {type, payload = {}} = {}) {
  if (type === LOCATION_CHANGE) {
    const location = payload.location || payload;
    const action = payload.action;

    return state
      .set('location', location)
      .set('action', action);
  }

  return state;
}

redux-immutable's People

Contributors

asaf avatar daleljefferson avatar gaearon avatar gajus avatar mathisonian avatar nathanhoad avatar salzhrani avatar suzdalnitski avatar velenir avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

redux-immutable's Issues

`CONSTRUCT` for creating initial state is not working

This is my reducer:

// reducers/query.js
let CONSTRUCT;

CONSTRUCT = () => {
    return {
        transportId: 1,
        fromDate: '2015-12-12',
        radius: 100000
    };
};

export default {
    CONSTRUCT
};
// reducers/index.js
export query from './query';

This is how I am creating the store:

initialState = {};
reducer = combineReducers(reducers);
state = reducer(initialState);
store = applyMiddleware(thunk, logger)(createStore)(reducer, state);

I was expecting to get what's returned by CONSTRUCT as state.query, but it fails with the error Uncaught Error: Action parameter value must be an object.

I think this is a bug. Please update me if I am missing something (/ doing something wrong).

Reducer state argument returns as a plain object

Hey all,
When I use a regular reducer function, I get the state argument as a plain JavaScript object rather than Immutable.js instance.
Is this the default behavior?
if so.. what are the benefits of using redux-immutable? and how to use it properly?

Why does the root state object need to be immutable?

I understand the benefits of immutable.js types for slices of the state that are updated by reducers, and therefore the performance benefit of performing a shallowEqual in shouldComponentUpdate, but what is the benefit of making the root state object an immutable.js type?

nested combineReducers

I'm having some trouble getting this library to work with my existing redux reducers. I believe the problem is that I am nesting multiple combineReducers calls in my root reducer.

So for a simplified example I have the following files:

// root-reducer.js
import { combineReducers } from 'redux-immutable';
import complexReducer from './complex-reducer';
export default combineReducers({
  complexReducer
});
// complex-reducer.js
import { combineReducers } from 'redux-immutable';
import reducerA from './reducer-a';
import reducerB from './reducer-b';
import reducerC from './reducer-c';

export default combineReducers({
  reducerA,
  reducerB,
  reducerC
});

When it tries to set the initial state of the complex reducer, it is passed in an undefined value from the root reducer and gives this error:

The previous state received by the reducer is of unexpected type. Expected argument to be an instance of Immutable.Iterable with the following properties: "reducerA", "reducerB", "reducerC".

and then fails on the withMutations call here because inputState is undefined.

This pattern is supported by redux (see reduxjs/redux#738). Is this possible in redux-immutable? Sorry if I am missing something obvious - am fairly new to the redux ecosystem.

State is undefined, can not get initial state

Hi guys,

i'm trying implement redux immutable in my project but i got stuck at connect mapStateToProps because the state returned from redux is Map object from ImmutableJS and i can not access user property also other properties in state by state.user or state.get('user') . So i posted my code here and need some advice from you guys, thanks in advance! Here is my code:

folder: store/configureStore.js


"use strict";

import {applyMiddleware, createStore} from 'redux';
import thunk from 'redux-thunk';
var promise = require('./promise');
var array = require('./array');
import rootReducers from '../reducers';
var createLogger = require('redux-logger');
var {AsyncStorage} = require('react-native');
import Immutable from 'immutable';

var isDebuggingInChrome = __DEV__ && !!window.navigator.userAgent;
const initialState = Immutable.Map({
    user: {
        isLoggedIn: false,
        username: null,
        session_id: null,
        name: null,
        uid: null
    }
});

var logger = createLogger({
  predicate: (getState, action) => isDebuggingInChrome,
  collapsed: true,
  duration: true,
});

var createCassiStore = applyMiddleware(thunk, promise, array, logger)(createStore)

function configureStore(onComplete: ?()=> void) {
    const store = createCassiStore(rootReducers, initialState);
    if (isDebuggingInChrome) {
        window.store = store;
    }
    return store;
}

module.exports = configureStore;

folder: reduders/user.js

'use strict'

import { createReducer } from 'redux-immutablejs'
import { fromJS } from 'immutable'

const initialState = fromJS({
    isLoggedIn: false,
    name: null,
    session_id: null,
    email: null,
    uid: null,
})

const user = createReducer(initialState, {
    'LOGGED_IN': (state, action) => state.merge({
        user: {
            isLoggedIn: true,
            ...action.data
        }
    })
});

module.exports = user

folder reducers/index.js

'use strict'

import {combineReducers} from 'redux-immutablejs';
import {reducer as formReducer} from 'redux-form/immutable';
import {userReducer} from './user';

export default combineReducers({
    form: formReducer,
    user: userReducer
});

folder components/MyNavigator.js

import { connect } from 'react-redux';
import React from 'react';
class MyNavigator extends React.Component {
     render() {
        return (
            <Navigator
                ref="navigator"
                style={{ backgroundColor: '#fff', flex: 1 }}
                initialRoute={{}}
                renderScene={this.renderScene}
            />
        );
    }

    renderScene(route, navigator) {
        if(route.signup)
            return <SignUpScene navigator={navigator} />
        if(route.home)
            return <HomeScene navigator={navigator}/>
        return <LoginScene navigator={navigator} />
    }
}
const mapStateToProps = state => {
    return {
        isLoggedIn: state.user.isLoggedIn || false // error here cannot get user of undefined
    }
}

module.exports = connect(mapStateToProps)(MyNavigator);

Dist directory out of date? Cannot resolve module 'canonical'

It looks like the dist directory is still referencing canonical in the combineReducers file, which no longer exists. Is that correct? Does it just need to be rebuilt and pushed to npm?

Full error: Cannot resolve module 'canonical' in /{path}/node_modules/redux-immutable/dist

Action validator throws on an action without a 'name' property (like the ones dispatched by the 'redux-devtools')

The "Canonical Reducer Composition" validator checks every action object and throws if a name property is missing. But redux uses another convention โ€“ it uses type, not name, so no action object has a proper name in it by default.

The core @@redux/INIT action is worked around and ignored in redux-immutable, but the redux-devtools use another action called @@INIT which isn't.

I'm not sure if this is an issue of redux-immutable or the redux itself, but hopefully you guys will figure it out. CC @gajus @gaearon

For now I'm willing to uninstall redux-immutable rather than redux-devtools (until the issue is fixed somehow).

Result from combineReducers not Immutable data type

Let me know if I'm doing the test wrong, but everything besides combineReducers passes this otherwise:

Mocha:

import expect from 'expect';
import Immutable from 'immutable';
import rootReducer from './index';
describe('combineReducers()', () => {
  it('should return an Immutable data type', () => {
    const expected = true;
    const actual = Immutable.Iterable.isIterable(rootReducer);
    expect(actual).toEqual(expected);
  });
});

This test fails. What am I doing wrong?

Redux 3.0.0 requires type property to be present in actions

Since redux 3.0.0 action creators require the 'type' property not to be undefined, i've played around with it and just added it with the same value as the 'name' property to get rid of the error.

The error thrown:
Uncaught Error: Actions may not have an undefined "type" property. Have you misspelled a constant?

Separate the canonical reducer composition pattern from combineReducers

This is a reminder for myself to look into implementing a combineReducers method that would work with Immutable.js data and a separate function that'd enable canonical reducer composition pattern.

The first bit is easy. The second bit in combination with the first option is tricky. One way of doing it would be as simple as providing two separate functions, combineReducers and canonicalCombineReducers.

This would make https://github.com/indexiatech/redux-immutablejs redundant since in essence it is trying to solve the same problem.

@asaf Do you have suggestions?

react-router-redux 4 instructions

I'm working from https://github.com/davezuko/react-redux-starter-kit if that helps explain my context.

This is the custom reducer I needed:

import Immutable from 'immutable';
import {
    LOCATION_CHANGE
} from 'react-router-redux';

let initialState;

initialState = Immutable.fromJS({
    locationBeforeTransitions: undefined
});

export default (state = initialState, action) => {
    if (action.type === LOCATION_CHANGE) {
        return state.merge({
            locationBeforeTransitions: action.payload
        });
    }

    return state;
};

I had to read the following to figure this out:

Also, I had to set up a custom "selectLocationState" selector to get immutable store values to be fed to Router correctly:

import createHistory from 'history/lib/createHashHistory';
// or: import createHistory from 'history/lib/createBrowserHistory';
import { useRouterHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';

const createSelectLocationState = () => {
  let prevRoutingState, prevRoutingStateJS;
  return (state) => {
    const routingState = state.get('routing'); // or state.routing 
    if (typeof prevRoutingState === 'undefined' || prevRoutingState !== routingState) {
      prevRoutingState = routingState;
      prevRoutingStateJS = routingState.toJS();
    }
    return prevRoutingStateJS;
  };
};

const browserHistory = useRouterHistory(createHistory)({
  basename: __BASENAME__
});
const history = syncHistoryWithStore(browserHistory, store, {
  selectLocationState: createSelectLocationState()
});

// pass above "history" to Router component as a prop

That's mentioned here:

Update: added createSelectLocationState fix

Remove sourcemap directives

Thanks for creating and maintaining this package.
Could you please remove sourcemap directives (//# sourceMappingURL=index.js.map) from compiled js files in dist directory. I'm using lots of packages in my project but only redux-immutable has these directives and it makes some minor but annoying problems with browserify.

Error: Reducer definition object must begin with a domain definition.

Hello i got Error: Reducer definition object must begin with a domain definition.
how to fix this error i really want to use redux-immubtale

store/store.js
/////////////////////////////////////////////////////////////////////////////////////////////////
import {createStore} from 'redux';
import {combineReducers} from 'redux-immutable';
import Immutable from 'immutable';
import * as reducers from '../reducers/reducers';
let app,
store,
state;
state = {};
state.setup = {};
state.listData = {
pageLimit: 10,
currentPage: 1,
searchValue: '',
data:{}
};
state = Immutable.fromJS(state);
app = combineReducers(reducers);
store = createStore(app, state);
export default store;
/////////////////////////////////////////////////////////////////////////////////////////////////
reducers/reducers.js
/////////////////////////////////////////////////////////////////////////////////////////////////
export default {
SETUP: (domain, action) => domain.set('setup',action.setupData),

listData: {

    SET_LIST (domain, action) {
        return domain.set('data', action.listData)
    },
    SET_CURENT_PAGE (domain, action) {
        return domain.set('currentPage', action.page)
    },
    SET_SEARCH (domain, action) {
        return domain.set('searchValue', action.word)
    },
    SET_PAGE_LIMIT (domain, action) {
        return domain.set('pageLimit', action.limit)
    }

}

};
/////////////////////////////////////////////////////////////////////////////////////////////////

combineReducers not imported

I'm attempting to use the combineReducers implementation provided here and use the suggested import syntax of:

 import { combineReducers } from 'npm:redux-immutable';

Note: I am using browserify so the package name must have the "npm:" prefix.

I get no errors on the import but if I log out the result of combineReducers I get undefined instead of a function. This is probably my error but any help you might have would be greatly appreciated.

redux-immutable and redux 3 initial state

Sounds like the redux-immutable library is not needed when working with redux 3 and above. But I was wondering if a function such as the one below would still be needed to combine the reducers into one immutable map?

export const combineReducers = (reducers) => {
  return (state = Immutable.Map(), action) => {
    return Object.keys(reducers).reduce((nextState, key) => {
      return nextState.set(key, reducers[key](state.get(key), action));
    }, state);
  };
};

Can't use Immutable record as root state after upgrading to 3.0.7

After upgrading to 3.0.7 i'm getting this error now:

(program):1 Uncaught TypeError: Value of argument "inputState" violates contract.

Expected:
?Immutable.Map

Got:
RootState {
  _map: Map {
    size: number;
    _root: void;
    __ownerID: void;
    __hash: void;
    __altered: boolean;
  };
}

use withMutations for better efficiency

I made my own reducer utilities for Immutable.js long before discovering this package, but I wanted to share an approach I think it might be helpful.

I was startled when looking into this package's code that combineReducers is just chaining .set calls. AFAIK this is not nearly as efficient as .withMutations. Moreover, when using .withMutations, the code becomes super-elegant. For example:

import {reduce, keys, identity} from 'lodash';

function combineImmutableReducersBase(reducers) {
  if (!keys(reducers).length) return identity;
  return (state, action) => state.withMutations(mutableState => reduce(
    reducers,
    (nextState, reducer, key) => nextState.update(key, value => reducer(value, action)),
    mutableState));
}

This function can easily be used to efficiently combine reducer map (a.k.a. action map) style reducers as well; if what you pass to combineImmutableReducers is (abstractly speaking) a multi-level map of prop name -> action type -> reducer, you just invert that into action type -> prop name -> reducer and do reducerMap(mapValues(multiLevelMap, combineImmutableReducers)). In real code (leaving out my implementation of reducerMap and composeReducers):

import {reduce, forEach, mapValues, keys, identity} from 'lodash';
import reducerMap from './reducerMap';
import composeReducers from './composeReducers';

function combineImmutableReducersBase(reducers) {
  if (!keys(reducers).length) return identity;
  return (state, action) => state.withMutations(mutableState => reduce(
    reducers,
    (nextState, reducer, key) => nextState.update(key, value => reducer(value, action)),
    mutableState));
}

export default function combineImmutableReducers(reducers) {
  let actionMap = {};
  let otherReducers = {};
  forEach(reducers, (reducer, key) => {
    if (reducer.actionMap) {
      // invert from prop name -> action type -> reducer 
      //          to action type -> prop name -> reducer
      forEach(reducer.actionMap, (reducer, type) => {
        (actionMap[type] || (actionMap[type] = {}))[key] = reducer;
      });
    }
    else {
      otherReducers[key] = reducer;
    }
  });

  return composeReducers(
    reducerMap(mapValues(actionMap, combineImmutableReducersBase)),
    combineImmutableReducersBase(otherReducers)
  );
}

React-router-redux selector documentation issue

I was having trouble implementing redux-immutable with react-router-redux using the selector described in the README.md.

I would receive the following error:

Uncaught TypeError: Cannot read property 'charAt' of undefined
    at matchRoutes

I believe this is because the example is only converting the routing state shallowly, and can be fixed by using:

return state.get('routing').toJS()

instead of:

return state.get('routing').toObject()

Trying to make it work with redux-auth

Hi,

This is not an issue but rather a question.
I am trying to make redux-auth work with redux-immutable. There is an issue because redux-auth tries to access the "auth" part of the state through state.auth, which of course does not work.

I would like to define a getter allowing access to auth via state.auth every time the state changes by doing:

Object.defineProperty(
  store.getState(), 
  'auth', { 
      get: function() { return this.get('auth'); 
  } 
});

That would fix this known issue.

Could you help me with that by telling me if it is possible or not?
I guess it is not a great solution but I think it would help many people.

Thanks in advance,
Cheers

combineReducer broken in 3.0.2

Fresh install of redux-immutable, double checked the package.json in the node_modules folder and it's definitely 3.0.2.

Get the following errors when trying to use combineReducers:

./~/redux-immutable/dist/combineReducers.js
Module not found: Error: Cannot resolve module 'lodash/forEach'

./~/redux-immutable/dist/utilities/getUnexpectedInvocationParameterMessage.js
Module not found: Error: Cannot resolve module 'lodash/filter'

./~/redux-immutable/dist/utilities/getUnexpectedInvocationParameterMessage.js
Module not found: Error: Cannot resolve module 'lodash/isEmpty'

./~/redux-immutable/dist/utilities/getUnexpectedInvocationParameterMessage.js
Module not found: Error: Cannot resolve module 'lodash/keys'

./~/redux-immutable/dist/utilities/validateNextState.js
Module not found: Error: Cannot resolve module 'lodash/isUndefined'

Likely related to #15

canonical reducers?

Hey all, is there any way to get an up to date working example of a simple redux-immutable app using canonical reducers?

About initialState

I am wondering why redux-immutable has no default state.

return (inputState, action) => {

Redux combineReducers has a default value. https://github.com/reactjs/redux/blob/6870b826b6b1bea7e7aec67a4ed88d139bd382cd/src/combineReducers.js#L111

I tried to nest redux-immutable combineReducers but it throws Cannot read property 'withMutations' of undefined because I did not specify the nested property in my global initialState Object.

Shouldn't it work without specifying the initialState.

Changelog ?

Would be great to have one (wanted to upgrade from 3.x to 4.x) :)

Reducer is not a function (within state tree)

Loving the ReduxImmutable library and using it's implementation of combineReducers for my root state without problem. However, I have a node off the state tree called forecast which I'd like to further separate into a set of reducers with the following:

import ReduxImmutable from 'npm:redux-immutable';
const { combineReducers } = ReduxImmutable;

import meta from './forecast/meta';
import history from './forecast/history';
import versions from './forecast/versions';

export default combineReducers({
  meta,
  history,
  versions
});

When I do this however, I get the message:

reducer is not a function

From the following code block:

2017-03-15_12-27-02

Any idea why this would be? For reference sake, here is the root reducer (which works so long as "forecast" is a regular reducer and not a combineReducer mutex):

import ReduxImmutable from 'npm:redux-immutable';
const { combineReducers } = ReduxImmutable;

import accounts from './accounts';
import counterparties from './counterparties';
import firebase from './firebase';
import forecast from './forecast';
import org from './org';
import registration from './registration';
import users from './users';
import userProfile from './userProfile';

export default combineReducers({
  accounts,
  counterparties,
  firebase,
  forecast,
  org,
  registration,
  users,
  userProfile
});

Import state from redux-devtools not work

When I try import state from file via redux-devtool - error happen.
inputState.withMutations((temporaryState)...
^^^^^^^^^^ - Object
https://github.com/gajus/redux-immutable/blob/master/src/combineReducers.js#L22
It might be useful to add a third argument in combineReducers.

For example in my case:
file
const fixer = state => Immutable.fromJS(state); // if state already immutable it do nothing
const store = createStore(rootReducer, initialState, fixer);
lib
fixer(inputState).withMutations((temporaryState)...

Sorry for my English.

Why can't I use Immutable.Record as initialState in rootReducer?

As I can see in https://medium.com/@fastphrase/practical-guide-to-using-immutablejs-with-redux-and-react-c5fd9c99c6b2 It should be possible to use Record as initialValue, but using combineReducers I get an Error, if I use Immutable.Record instead of Immutable.Map in redux createStore . Please explain.

I use redux-immutable's combineReducers and all my reducers now made with Immutable.Record.
But as it is in example in redux-immutable github examples, store should be created with Immutable.Map as initialState.

const initialState = Immutable.Map()
const store = createStore(rootReducer, initialState)

I tried to change it to

const initialState = Immutable.Record()
const store = createStore(rootReducer, initialState)

But I'm getting errors from Immutable lib. Is there some workaround? It could be very helpful, if someone point me in the right direction.

PS. "react-redux": "5.0.5"

The main reason for the issue is API.

Using Record as initialState allows to get data from state in connected components I can:

export default connect(
  state => ({
    someProp: state.reducer.value
  })
)(SomeComponent)

With Map i can only get data:

export default connect(
  state => ({
    someProp: state.getIn(['reducer', 'value'])
  })
)(SomeComponent)

Uncaught TypeError: reducer is not a function

Hey guys,
Thanks for an awesome repo,
I updated to the latest version and ran into this error,

Uncaught TypeError: reducer is not a function at combineReducers.js:51 ( using Webpack )

My code:

var state = Immutable.Map({});

var itemsReducer = {

    items: {

        CONSTRUCT () {
            return Immutable.Map([
                {
                    id: 1,
                    name: 'foo',
                    done: true
                },
                {
                    id: 2,
                    name: 'bar',
                    done: false
                },
                {
                    id: 3,
                    name: 'baz',
                    done: false
                }
            ])
        },

        ADD_ITEM (domain, action) {
            return domain
                .push(Immutable.Map({
                    id: 1,
                    name: 'test',
                    done: false
                }));
        }
    }
};

var reducer = combineReducers({
    items: itemsReducer
});

Only happens with the latest version,
Am I missing something?

selectLocationState function appears to cause render without state change

I noticed the other day that my entire app was being rendered more frequently than expected. I eventually tracked this down to the Router component, which seemed to be rendering on every new action. I think the cause of this may be the selectLocationState function described in the docs, which invokes toJS on the routing state subtree. As I understand it, this creates a new JavaScript object every time the function is called, which is not equal to the previous object even if it contains the same data, causing React to re-render the Router. I tried replacing this with a memoized function that would return an identical object for the same state, and this appeared to fix the problem:

const history = syncHistoryWithStore(browserHistory, store, {
  selectLocationState: (function () {
    let prevState;
    let prevStateJS;
    function selectLocationStateHelper(state) {
      const newState = state.get('routing');
      if (!newState.equals(prevState)) {
        prevState = newState;
        prevStateJS = newState.toJS();
      }
      return prevStateJS;
    }
    return selectLocationStateHelper;
  }()),
});

Does it make sense to do something along these lines?

Reducer should be able to return a string or int or bool

I tried to return string in reducers like

export default combineReducers({
  searchTerm: {
    SEARCH (domain, action) {
      return action.data.text;
    },
  },
}

but I got a error says Reducer must return an instance of Immutable.

I think reducer should be able to return a string or int or bool because they are immutable already.

Usage examples are out of date

I think there's an error in the readme

reduxRouterMiddleware.listenForReplays(store, (state) => {
    return state.getIn([
        'route',
        'locationBeforeTransitions'
    ]).toJS();
});

should be

reduxRouterMiddleware.listenForReplays(store, (state) => {
    return state.get('route').toJS();
});

because otherwise it throws an error when 'locationBeforeTransitions' null.

In fact, in the last version of react-router-redux we have to pass the function to the syncHistoryWithStore

const history = syncHistoryWithStore(browserHistory, store, {selectLocationState: (state) => state.get('routes').toJS()})

I didn't test it yet, I'll do it the weeekend, but if you agree I'll do a pull request.

some question of nesting multiply combineReducers

sorry to trouble, I'm ensure how does combineReducers handle nested state object,

I mean if I define the state structure like below:

import { Map } from 'immutable';
import { handleActions } from 'redux-actions'

const rootReducer = combineReducers({
  child1Reducer: combineReducers({
    child2Reducer: handleActions({
        [ACTION]: (state, action) => {
          const { payload: { id, }} = action;
          return state.set('id', id);
        }
      }, Map({}))
  }),
})

my state tree is like:

{
  child1Reducer: {
    child2Reducer: {
      id: ....
    }
  }
}

My question is,

  1. is that state on top level immutable? I mean the whole state tree
  2. is that each child immutable? like state.child1Reducer or state.child1Reducer.child2Reducer
  3. if I call once state.toJS() in connect() under react-redux api, are all children convert to plain javascript object?

thanks for your time,

regards.

more examples

It would be nice to have more examples or an example-application which shows dispatching actions and the rendering of data in components.

combineReducers in child reducers

Hello, I am a beginner in redux and immutable.js

I found something weird with combineReducers.

When I use redux-immutable in child reducers. The error always there.

My Code is like this:

import { combineReducers } from 'redux-immutable'
import foo from './fooReducers'
import bar from './barReducers'
import { getReducersFromOthers } from './bazReducers' // It return an Object. and it works without combine child reducers

let rootReducers = {
    foo,
    bar
}

rootReducers['others'] = combineReducers(getReducersFromOthers())

export default rootReducers
// warning.js:14 Store does not have a valid reducer. Make sure the argument passed to combineReducers is an object whose values are reducers.

I notice that redux.combineReducers and redux-immutable.combineReducers are returned different things.

I want to know is how can I use combineReducers with child reducers.

Sorry for my English. I hope you could understand what I said.
Thanks

reducer is not a function

I keep running into the error reducer is not a function.

Not sure what I'm doing wrong? My state is a plain object and some of the keys within state are Immutable

redux/modules/rootReducer.js:

import { combineReducers } from 'redux-immutable';
import { routeReducer } from './routeReducer';

export default combineReducers({
  routing: routeReducer,
});

redux/modules/routeReducer.js:

import Immutable from 'immutable';
import { LOCATION_CHANGE } from 'react-router-redux';

const initialState = Immutable.fromJS({
  locationBeforeTransitions: null
});

const locationChangeReducer = (state, action) => {
  return Object.assign({}, state, {locationBeforeTransitions: action.payload});
};

export default function routeReducer(state = initialState, action) {
  switch (action.type) {
    case LOCATION_CHANGE: return locationChangeReducer(state, action);
    default: return state;
  }
}

redux/createStore.js:

import { createStore as _createStore, applyMiddleware, compose } from 'redux';
import createMiddleware from './middleware/clientMiddleware';
import { routerMiddleware } from 'react-router-redux';
import reducer from './modules/reducer';
import { persistState } from 'redux-devtools';
import { DevTools } from 'containers';

export default function createStore(history, client, data) {
  // Sync dispatched route actions to the history
  const reduxRouterMiddleware = routerMiddleware(history);

  const middleware = [createMiddleware(client), reduxRouterMiddleware];

  let finalCreateStore;
  if (_DEVELOPMENT__ && __CLIENT__ && __DEVTOOLS__) {
    finalCreateStore = compose(
      applyMiddleware(...middleware),
      window.devToolsExtension ? window.devToolsExtension() : DevTools.instrument(),
      persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))
    )(_createStore);
  } else {
    finalCreateStore = applyMiddleware(...middleware)(_createStore);
  }

  const store = finalCreateStore(reducer, data);

  if (__DEVELOPMENT__ && module.hot) {
    module.hot.accept('./modules/reducer', () => {
      store.replaceReducer(reducer);
    });
  }

  return store;
}

does redux-immutable expect reducers to be part of the state?

If I pass an initialState like so createStore(combineReducers({reducer1, reducer2}), initialState), I get:

Unexpected properties .... found in previous state received by the reducer. Expected to find one of the known reducer property names instead 'reducer1', 'reducer2'

When I look at my state which is defined as Immutable.Map, I see reducer1 and reducer2 keys at the roots. Does redux-immutable reconstruct state by creating root keys using the reducer names?

Allow storing state as a Record

Is there a particular reason you define your state as a Map?

Usually you know the state structure beforehand and it's not dynamic in any way plus it would make it easier to access the state (instead of using get).

The only downside I can see is that you need to create a predefined StateRecord containing all the state properties beforehand which you would pass to combineReducers. Each time you add a reducer you need to update this record.

Any thoughts?

v3.0.9 not on npm registry

Hi, it appears that this package's last version, released more than a month ago, is not yet on the npm registry:

npm ERR! notarget No compatible version found: redux-immutable@'>=3.0.9 <4.0.0'
npm ERR! notarget Valid install targets:
npm ERR! notarget 1.1.2, 1.1.3, 1.1.4, 1.1.5, 1.2.0, 1.2.1, 1.2.2, 1.2.3, 1.3.0, 1.3.2, 1.3.3, 1.3.4, 1.3.5, 1.3.6, 1.3.7, 1.3.10, 2.0.0, 2.0.1, 2.0.2, 3.0.0, 3.0.1, 3.0.2, 3.0.3, 3.0.4, 3.0.5, 3.0.6, 3.0.7, 3.0.8

https://www.npmjs.com/package/redux-immutable

Consider dropping dependency on Lodash

Lodash isn't a tiny library so it's better not to drag it completely just for a couple of functions. foreach, isEmpty, filter, and isUndefined are easy to replace with plain JS constructs. If there is a real reason for using Lodash implementations, it would still be better to import individual functions.

Finally, what do you think about making immutable a peer dependency? We certainly never want to have a duplicate immutable, and this library doesn't make sense unless you're already using immutable, so peer looks like the right solution to avoid duplicate installations.

React-router <Link> does not work

I am using this package with react-redux-router. While manually changing the URL in my browser does follow my routes and take me to the correct page, if I try to use the <Link> component provided by react-router (or even use the push action creator from react-redux-router) nothing happens. A link gets created and I can inspect and see it has the correct href, but clicking on it does nothing.

I believe this is probably an issue with the history not syncing correctly with the store, but I feel like I am following the documentation correctly. Has anyone else been successful in using that component with this package? Not sure if I'm doing something wrong or if this is a real bug.

react v0.14.8
react-router v2.3.0
react-router-redux v4.0.2
redux-immutable v3.0.6

I am adding the LOCATION_CHANGE reducer. Note that while I call it routing here, I have also called it route and routes to no avail.

reducers.js

import Immutable from 'immutable';
import { LOCATION_CHANGE } from 'react-router-redux';

const initialState = Immutable.fromJS({
    location: {}
});

export function routing(state = initialState, action) {
    if (action.type === LOCATION_CHANGE) {
        return state.merge({
            location: action.payload
        })
    }

    return state
}

I have a custom store configuration file where I add combineReducers from this package.

configureStore.js

import { createStore, applyMiddleware } from 'redux'
import promiseMiddleware from './middleware/promise-middleware'
import { routing } from './reducers'
import { combineReducers } from 'redux-immutable'

export default function(data) {
  const reducer = combineReducers({
    routing: routing
  })

  const store = createStore(
    reducer,
    applyMiddleware(promiseMiddleware)
  )

  return store
}

Then I add this store, sync it with the router history, and add it to my app wrapper (that gets loaded into the DOM). This is where I suspect the problems are coming in. Once again, while I call the piece of state routing here, I have also tried route and routes.

app.js

import React from 'react'
import { Component } from 'react'
import { Provider } from 'react-redux'
import { Router, useRouterHistory } from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
import { createHistory, useBasename  } from 'history'
import createBrowserHistory from 'history/lib/createBrowserHistory'
import makeRoutes from '../routes'
import createStore from '../configureStore'
import Immutable from 'immutable'

const browserHistory = useRouterHistory(createBrowserHistory)({
  basename: '/baseurl'
})
const store = createStore()
const history = syncHistoryWithStore(browserHistory, store, {
  selectLocationState: (state) => {
    return state.getIn(['routing', 'location']).toJS()
  },
})
const routes = makeRoutes(store)

class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <Router history={history} routes={routes} />
      </Provider>
    )
  }
}

export default App

Any thoughts on why the <Link> component wouldn't be working with a setup like this?

Update from 3.0.9 to 3.0.10 causes flow-runtime errors

Not sure whether this is the right place, but ran into got the following scenario and I at least want to mention it in case others run into the same problems:

I got this repo which is statically typed using Flow. Recently I decided to update some packages, including redux-immutable: from 3.0.9 to 3.0.10. Right after this update I got the following list of when kicking off my webpack build:

 [1314] ./~/react-hot-loader/index.js 41 bytes {0} [built]
 [1536] multi react-hot-loader/patch webpack-hot-middleware/client babel-polyfill ./src/index.js ./src/style/main.css 76 bytes {0} [built]
     + 1522 hidden modules

ERROR in node_modules/flow-runtime/src/TypeContext.js:128
128:   [ParentSymbol]: ? TypeContext;
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ computed property keys not supported

node_modules/flow-runtime/src/TypeContext.js:131
131:   [NameRegistrySymbol]: NameRegistry = {};
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ computed property keys not supported

node_modules/flow-runtime/src/TypeContext.js:134
134:   [TypePredicateRegistrySymbol]: TypePredicateRegistry = {};
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ computed property keys not supported

node_modules/flow-runtime/src/TypeContext.js:137
137:   [TypeConstructorRegistrySymbol]: TypeConstructorRegistry = new Map();
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ computed property keys not supported

node_modules/flow-runtime/src/TypeContext.js:140
140:   [InferrerSymbol]: TypeInferrer = new TypeInferrer(this);
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ computed property keys not supported

node_modules/flow-runtime/src/TypeContext.js:143
143:   [ModuleRegistrySymbol]: ModuleRegistry = {};
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ computed property keys not supported

node_modules/flow-runtime/src/TypeContext.js:146
146:   [CurrentModuleSymbol]: ? ModuleDeclaration;
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ computed property keys not supported

node_modules/flow-runtime/src/TypeContext.js:160
160:     context[ParentSymbol] = this;
         ^^^^^^^^^^^^^^^^^^^^^ assignment of computed property/element. Indexable signature not found in
160:     context[ParentSymbol] = this;
         ^^^^^^^ TypeContext

node_modules/flow-runtime/src/TypeContext.js:171
171:     const inferrer = this[InferrerSymbol];
                          ^^^^^^^^^^^^^^^^^^^^ access of computed property/element. Indexable signature not found in
171:     const inferrer = this[InferrerSymbol];
                          ^^^^ TypeContext

node_modules/flow-runtime/src/TypeContext.js:179
179:     const item = this[NameRegistrySymbol][name];
                      ^^^^^^^^^^^^^^^^^^^^^^^^ access of computed property/element. Indexable signature not found in
179:     const item = this[NameRegistrySymbol][name];
                      ^^^^ TypeContext

node_modules/flow-runtime/src/TypeContext.js:189
189:     const parent = this[ParentSymbol];
                        ^^^^^^^^^^^^^^^^^^ access of computed property/element. Indexable signature not found in
189:     const parent = this[ParentSymbol];
                        ^^^^ TypeContext

node_modules/flow-runtime/src/TypeContext.js:269
269:       return input[TypeSymbol];
                  ^^^^^^^^^^^^^^^^^ mixed. This type is incompatible with the expected return type of
266:   getAnnotation <T> (input: T): ? Type<T> {
                                       ^^^^^^^ Type

node_modules/flow-runtime/src/TypeContext.js:269
269:       return input[TypeSymbol];
                        ^^^^^^^^^^ Symbol. This type is incompatible with
266:   getAnnotation <T> (input: T): ? Type<T> {
                      ^ string

node_modules/flow-runtime/src/TypeContext.js:316
316:       const moduleRegistry: ModuleRegistry = (this: $FlowIssue<252>)[ModuleRegistrySymbol];
                                                         ^^^^^^^^^^^^^^^ identifier `$FlowIssue`. Could not resolve name

node_modules/flow-runtime/src/TypeContext.js:325
325:       const nameRegistry: NameRegistry = (this: $FlowIssue<252>)[NameRegistrySymbol];
                                                     ^^^^^^^^^^^^^^^ identifier `$FlowIssue`. Could not resolve name

node_modules/flow-runtime/src/TypeContext.js:350
350:     const nameRegistry: NameRegistry = (this: $FlowIssue<252>)[NameRegistrySymbol];
                                                   ^^^^^^^^^^^^^^^ identifier `$FlowIssue`. Could not resolve name

node_modules/flow-runtime/src/TypeContext.js:357
357:     const moduleRegistry: ModuleRegistry = (this: $FlowIssue<252>)[ModuleRegistrySymbol];
                                                       ^^^^^^^^^^^^^^^ identifier `$FlowIssue`. Could not resolve name

node_modules/flow-runtime/src/TypeContext.js:364
364:     const moduleRegistry: ModuleRegistry = (this: $FlowIssue<252>)[ModuleRegistrySymbol];
                                                       ^^^^^^^^^^^^^^^ identifier `$FlowIssue`. Could not resolve name

node_modules/flow-runtime/src/TypeContext.js:380
380:     const nameRegistry: NameRegistry = (this: $FlowIssue<252>)[NameRegistrySymbol];
                                                   ^^^^^^^^^^^^^^^ identifier `$FlowIssue`. Could not resolve name

node_modules/flow-runtime/src/TypeContext.js:398
398:       const handlerRegistry = this[TypeConstructorRegistrySymbol];
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access of computed property/element. Indexable signature not found in
398:       const handlerRegistry = this[TypeConstructorRegistrySymbol];
                                   ^^^^ TypeContext

node_modules/flow-runtime/src/TypeContext.js:411
411:     const handlerRegistry = this[TypeConstructorRegistrySymbol];
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access of computed property/element. Indexable signature not found in
411:     const handlerRegistry = this[TypeConstructorRegistrySymbol];
                                 ^^^^ TypeContext

node_modules/flow-runtime/src/TypeContext.js:500
500:     const typeParameters = subject[TypeParametersSymbol];
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access of computed property/element. Computed property cannot be accessed with
500:     const typeParameters = subject[TypeParametersSymbol];
                                        ^^^^^^^^^^^^^^^^^^^^ Symbol

node_modules/flow-runtime/src/TypeContext.js:517
517:     innerContext[ParentSymbol] = this;
         ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment of computed property/element. Indexable signature not found in
517:     innerContext[ParentSymbol] = this;
         ^^^^^^^^^^^^ TypeContext

node_modules/flow-runtime/src/TypeContext.js:519
519:     innerContext[CurrentModuleSymbol] = target;
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment of computed property/element. Indexable signature not found in
519:     innerContext[CurrentModuleSymbol] = target;
         ^^^^^^^^^^^^ TypeContext

node_modules/flow-runtime/src/TypeContext.js:527
527:     const currentModule: ModuleDeclaration = (this: $FlowIssue<252>)[CurrentModuleSymbol];
                                                         ^^^^^^^^^^^^^^^ identifier `$FlowIssue`. Could not resolve name

node_modules/flow-runtime/src/TypeContext.js:778
778:       const handlerRegistry = this[TypeConstructorRegistrySymbol];
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access of computed property/element. Indexable signature not found in
778:       const handlerRegistry = this[TypeConstructorRegistrySymbol];
                                   ^^^^ TypeContext

node_modules/flow-runtime/src/TypeContext.js:834
834:     return makeReactPropTypes((type.unwrap(): $FlowIgnore));
                                                   ^^^^^^^^^^^ identifier `$FlowIgnore`. Could not resolve name

node_modules/flow-runtime/src/TypeInferrer.js:55
 55:     else if (typeof input === 'symbol') {
                                   ^^^^^^^^ string literal `symbol`. This value is not a valid `typeof` return value

node_modules/flow-runtime/src/cache.js:50
 50:   return (subject: $FlowIgnore);
                        ^^^^^^^^^^^ identifier `$FlowIgnore`. Could not resolve name

node_modules/flow-runtime/src/cache.js:93
 93:       (subject: $FlowIgnore).set(param, child);
                     ^^^^^^^^^^^ identifier `$FlowIgnore`. Could not resolve name

node_modules/flow-runtime/src/declarations/ModuleDeclaration.js:30
 30:   get moduleType (): 'commonjs' | 'es6' {
       ^ Potentially unsafe get/set usage. Getters and setters with side effects are potentially unsafe and disabled by default. You may opt-in to using them anyway by putting `unsafe.enable_getters_and_setters=true` into the [options] section of your .flowconfig.

node_modules/flow-runtime/src/declarations/ModuleDeclaration.js:39
 39:   get isCommonJS (): boolean {
       ^ Potentially unsafe get/set usage. Getters and setters with side effects are potentially unsafe and disabled by default. You may opt-in to using them anyway by putting `unsafe.enable_getters_and_setters=true` into the [options] section of your .flowconfig.

node_modules/flow-runtime/src/declarations/ModuleDeclaration.js:43
 43:   get isES6 (): boolean {
       ^ Potentially unsafe get/set usage. Getters and setters with side effects are potentially unsafe and disabled by default. You may opt-in to using them anyway by putting `unsafe.enable_getters_and_setters=true` into the [options] section of your .flowconfig.

node_modules/flow-runtime/src/declarations/ModuleDeclaration.js:47
 47:   get declarations (): DeclarationDict {
       ^ Potentially unsafe get/set usage. Getters and setters with side effects are potentially unsafe and disabled by default. You may opt-in to using them anyway by putting `unsafe.enable_getters_and_setters=true` into the [options] section of your .flowconfig.

node_modules/flow-runtime/src/declarations/ModuleDeclaration.js:49
 49:     return (innerContext: $FlowIssue<252>)[NameRegistrySymbol];
                               ^^^^^^^^^^^^^^^ identifier `$FlowIssue`. Could not resolve name

node_modules/flow-runtime/src/declarations/ModuleDeclaration.js:52
 52:   get modules (): ModuleDeclarationDict {
       ^ Potentially unsafe get/set usage. Getters and setters with side effects are potentially unsafe and disabled by default. You may opt-in to using them anyway by putting `unsafe.enable_getters_and_setters=true` into the [options] section of your .flowconfig.

node_modules/flow-runtime/src/declarations/ModuleDeclaration.js:54
 54:     return (innerContext: $FlowIssue<252>)[ModuleRegistrySymbol];
                               ^^^^^^^^^^^^^^^ identifier `$FlowIssue`. Could not resolve name

node_modules/flow-runtime/src/declarations/TypeDeclaration.js:19
 19:   get type (): Type<T> {
       ^ Potentially unsafe get/set usage. Getters and setters with side effects are potentially unsafe and disabled by default. You may opt-in to using them anyway by putting `unsafe.enable_getters_and_setters=true` into the [options] section of your .flowconfig.

node_modules/flow-runtime/src/decorateFunction.test.js:63
 63:       return decorated('hello ', {nope: true});
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function call
 63:       return decorated('hello ', {nope: true});
                                      ^^^^^^^^^^^^ object literal. This type is incompatible with
 43:     function adder <A: number | string, B: number | string> (a: A, b: B): A | B {
                            ^^^^^^^^^^^^^^^ union: number | string
  Member 1:
   43:     function adder <A: number | string, B: number | string> (a: A, b: B): A | B {
                              ^^^^^^ number
  Error:
   63:       return decorated('hello ', {nope: true});
                                        ^^^^^^^^^^^^ object literal. This type is incompatible with
   43:     function adder <A: number | string, B: number | string> (a: A, b: B): A | B {
                              ^^^^^^ number
  Member 2:
   43:     function adder <A: number | string, B: number | string> (a: A, b: B): A | B {
                                       ^^^^^^ string
  Error:
   63:       return decorated('hello ', {nope: true});
                                        ^^^^^^^^^^^^ object literal. This type is incompatible with
   43:     function adder <A: number | string, B: number | string> (a: A, b: B): A | B {
                                       ^^^^^^ string

node_modules/flow-runtime/src/decorateFunction.test.js:63
 63:       return decorated('hello ', {nope: true});
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function call
 63:       return decorated('hello ', {nope: true});
                                      ^^^^^^^^^^^^ object literal. This type is incompatible with
 43:     function adder <A: number | string, B: number | string> (a: A, b: B): A | B {
                                                ^^^^^^^^^^^^^^^ union: number | string
  Member 1:
   43:     function adder <A: number | string, B: number | string> (a: A, b: B): A | B {
                                                  ^^^^^^ number
  Error:
   63:       return decorated('hello ', {nope: true});
                                        ^^^^^^^^^^^^ object literal. This type is incompatible with
   43:     function adder <A: number | string, B: number | string> (a: A, b: B): A | B {
                                                  ^^^^^^ number
  Member 2:
   43:     function adder <A: number | string, B: number | string> (a: A, b: B): A | B {
                                                           ^^^^^^ string
  Error:
   63:       return decorated('hello ', {nope: true});
                                        ^^^^^^^^^^^^ object literal. This type is incompatible with
   43:     function adder <A: number | string, B: number | string> (a: A, b: B): A | B {
                                                           ^^^^^^ string

node_modules/flow-runtime/src/decorateGeneratorFunction.js:34
 34:     return result;
         ^^^^^^^^^^^^^^ Generator. This type is incompatible with the expected return type of
 18:   const decorated = function *decorated (...args: any[]): G {
                                                               ^ some incompatible instantiation of `G`

node_modules/flow-runtime/src/errorReporting/__tests__/makeJSONError.test.js:259
259:     @t.decorate(IThing)
          ^^^^^^^^^^^^^^^^^^ Experimental decorator usage. Decorators are an early stage proposal that may change. Additionally, Flow does not account for the type implications of decorators at this time.

node_modules/flow-runtime/src/errorReporting/__tests__/makeJSONError.test.js:264
264:     @t.decorate(IInvalid)
          ^^^^^^^^^^^^^^^^^^^^ Experimental decorator usage. Decorators are an early stage proposal that may change. Additionally, Flow does not account for the type implications of decorators at this time.

node_modules/flow-runtime/src/typed.test.js:221
221:     @t.decorate(t.object(
          ^ Experimental decorator usage. Decorators are an early stage proposal that may change. Additionally, Flow does not account for the type implications of decorators at this time.

node_modules/flow-runtime/src/typed.test.js:237
237:     @t.decorate(t.object(
          ^ Experimental decorator usage. Decorators are an early stage proposal that may change. Additionally, Flow does not account for the type implications of decorators at this time.

node_modules/flow-runtime/src/types/ParameterizedFunctionType.js:20
 20:   get partial (): PartialType<(...params: P[]) => R> {
       ^ Potentially unsafe get/set usage. Getters and setters with side effects are potentially unsafe and disabled by default. You may opt-in to using them anyway by putting `unsafe.enable_getters_and_setters=true` into the [options] section of your .flowconfig.

node_modules/flow-runtime/src/types/ParameterizedFunctionType.js:28
 28:   get typeParameters (): TypeParameter<X>[] {
       ^ Potentially unsafe get/set usage. Getters and setters with side effects are potentially unsafe and disabled by default. You may opt-in to using them anyway by putting `unsafe.enable_getters_and_setters=true` into the [options] section of your .flowconfig.

node_modules/flow-runtime/src/types/ParameterizedFunctionType.js:32
 32:   get params (): FunctionTypeParam<P>[] {
       ^ Potentially unsafe get/set usage. Getters and setters with side effects are potentially unsafe and disabled by default. You may opt-in to using them anyway by putting `unsafe.enable_getters_and_setters=true` into the [options] section of your .flowconfig.

node_modules/flow-runtime/src/types/ParameterizedFunctionType.js:36
 36:   get rest (): ? FunctionTypeRestParam<P> {
       ^ Potentially unsafe get/set usage. Getters and setters with side effects are potentially unsafe and disabled by default. You may opt-in to using them anyway by putting `unsafe.enable_getters_and_setters=true` into the [options] section of your .flowconfig.

node_modules/flow-runtime/src/types/ParameterizedFunctionType.js:40
 40:   get returnType (): Type<R> {
       ^ Potentially unsafe get/set usage. Getters and setters with side effects are potentially unsafe and disabled by default. You may opt-in to using them anyway by putting `unsafe.enable_getters_and_setters=true` into the [options] section of your .flowconfig.


... 9 more errors (only 50 out of 59 errors displayed)
To see all errors, re-run Flow with --show-all-errors

I downgraded every single package until the version bump of redux-immutable was the only one left. Globally scrolling through the commits done for 3.0.10 I'm not sure why this suddenly occurs.

set-up help

Hey there, just trying to convert a current app to deal with immutable state and running into some troubles. The state my components are receiving are still in the Immutable.js form.

Map {size: 9, _root: BitmapIndexedNode, __ownerID: undefined, __hash: undefined, __altered: false}

Any help will be great as I cant seem to figure out where exactly im going wrong although I think its the way im orgainsing configureStore.js below. (I've taken the majority of the app out for simplicity)

thanks

reducer.js:

import { REHYDRATE } from 'redux-persist/constants';
import Immutable from 'immutable';

const initialState = Immutable.Map({
  rehydrated: false,
  isLoggedIn: false
});

const Login = (state = initialState, action) => {
  switch (action.type) {
  case REHYDRATE:
    const incoming = action.payload;
    if (incoming.reducers) {
      return state.merge(incoming.reducers.login).set('rehydrated', true);
    }
    return state.set('rehydrated', true);
  case 'AUTHORISE_SUCCESS':
    return state.set('isLoggedIn', true);
  case 'AUTHORISE_FAILURE':
    return state.set('isLoggedIn', false);
  case 'LOGOUT_SUCCESS':
    return state.set('isLoggedIn', false);
  default:
    return state;
  }
};

export default Login;

combineReducers.js:

import { combineReducers } from 'redux-immutable';

import login from './login';
import routing from './routing';

const rootReducer = combineReducers({
  login,
  routing
});

export default rootReducer;

configureStore.js:

import thunkMiddleware from 'redux-thunk';
import { autoRehydrate } from 'redux-persist';
import { routerMiddleware } from 'react-router-redux';
import rootReducer from '../reducers/index';
import { createStore, applyMiddleware, compose } from 'redux';
import Immutable from 'immutable';


const initialState = Immutable.Map();

export default function configureStore(browserHistory) {
  return createStore(
    rootReducer,
    initialState,
    compose(
      autoRehydrate(),
      applyMiddleware(thunkMiddleware, routerMiddleware(browserHistory))
    )
  );
}

export default configureStore;

index.js:

import * as React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { syncHistoryWithStore } from 'react-router-redux';
import { Router, Route, browserHistory } from 'react-router';

import AuthCheckHOC from './components/AuthCheckHOC';
import PersisterHOC from './components/PersisterHOC';
import Container from './containers/Container';
import Auth from './containers/Auth';

import configureStore from './store/configureStore';

const store = configureStore(browserHistory);
const history = syncHistoryWithStore(browserHistory, store, {
  selectLocationState(state) {
    return state.get('routing').toJS();
  }
});
ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>
      {/*'/signin' route needs to be outside PersisterHOC and AuthCheckHOC*/}
      <Route path="/signin" component={Auth} />
      <Route component={PersisterHOC(AuthCheckHOC(Container), store)}>
      </Route>
    </Router>
  </Provider>,
  document.getElementById('react-content')
);

initialState rootReducer, serialise/ desialise state maintaining types

Let's say I have a reducer with initialState:

myReducer

Immutable.fromJS({
  uniqueTodos: Immutable.Set([ 'one', 'two' ])
});

Then time to save to local store:

const storeSaveObj = store.getState().toJS();
saveToLocalStorage(JSON.stringify(storeSaveObj));

Then to restore it:

import { getStateFromLocalStorage } from './utils'; 
import { immutableRootReducer } from './rootReducer';
import { createStore } from 'redux';

const initialState = Immutable.fromJS(getStateFromLocalStorage());
const store = createStore(immutableRootReducer, initialState);

Then the reducer has been restored, but as a Immutable.List because of Immutable.fromJS:

const uniqueTodos = store.getState().getIn([ 'myReducer', 'uniqueTodos' ]);
Immutable.List.isList(uniqueTodos);
true
Immutable.Set.isSet(uniqueTodos);
false

Is there a good solution to retain the immutable types somehow?

Reducer is not a function ?

I'm getting uncaught typeError: reducer is not a function from combineReducers.js. When I check typeof reducer, it is a function.

Does anyone know why I'm getting this error?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.