reduxjs / redux

A JS library for predictable global state management
https://redux.js.org
MIT License
60.88k stars 15.27k forks source link

How to initialize redux with immutable object #153

Closed amorphius closed 9 years ago

amorphius commented 9 years ago

Is it possible or I'm doing smt wrong?

let initialState = immutable.fromJS({some_store: "some initial data"});
const redux = createRedux(stores, initialState);
...
export function some_store(state, action) {
    // state is undefined here
}
emmenko commented 9 years ago

I think what you want is something like this

// stores/some-store.js
import Immutable from 'immutable'

const { Map, List, fromJS } = Immutable
const initialState = Map({
  foo: 'bar',
  fooList: List()
})

export function someStore (state = initialState, action) {
  if (action.type === 'FOO') {
    return state.set('foo', fromJS(action.foo))
  }
  if (action.type === 'FOO_LIST') {
    return state.set('fooList', fromJS(action.fooList))
  }

  return state
}

// stores/index.js
export { default as someStore } from './some-store'

// application.js
import * as stores from './stores'

const redux = createRedux(stores)
gaearon commented 9 years ago

You should let stores define their own initial state using default parameter like @emmenko showed.

The initialState argument is only meant to be used for rehydrating state from server or localStorage. (@acdlite, we might want to explain this in docs.)

That said, what you tried should work. Can somebody investigate?

amorphius commented 9 years ago

No, what I tried does not work. I just want to create initial data for all stores in one place. I guess this is what I shouldn't do.

gaearon commented 9 years ago

I just want to create initial data for all stores in one place. I guess this is what I shouldn't do.

It's up to you. I find it better to divide the initial data.

Still, if something doesn't work, let's keep it open? I'll revisit next week and see why it did not work.

leoasis commented 9 years ago

The problem is with composeStores that is assuming the root state is a plain JS object, and accessing the properties with state[key], which fails with Immutable.Map. I think it may work with Immutable.Record since that makes the fields accessible via regular JS properties.

There may be other places where it's assuming a plain object though.

gaearon commented 9 years ago

Oh. That's a great catch! Thanks for explaining. This makes perfect sense.

pierregm commented 9 years ago

Using connectors also fails for the very same reason: isPlainObject(Immutable.Record) === false .

gaearon commented 9 years ago

@pierregm This is actually correct. If it spread the Record properties over the component props, that wouldn't work anyway. It is up to you to write select={state => state.get('something').toJS()}.

owais commented 9 years ago

I was able to get it to work like this,

// store
const initialState = Immutable.fromJS({}).toOrderedMap();

export default function streamStore(state = initialState, action) {
  switch (action.type) {

    case actionTypes.FETCH_STREAM_DONE:
      var streamMap = {};

      for (var i in action.stream_data) {
        var item = action.stream_data[i];
        streamMap[item.id] = item;
      }
      return state.merge(Immutable.fromJS(streamMap).toOrderedMap());

    default:
      return state
  }
};

// select
function select(state) {
  return {stream: state.stream.toList()}
}

It works perfectly but it ends up re-rendering all items in the stream (a list view). I was wondering how one could implement something that compares the old state vs new state at store level and invalidates the need to render any components right there when there are no changes to the data. NuclearJS does this with Immutable structures. What would the recommended way be to implement something like that in redux?

gaearon commented 9 years ago

@owais

Check out Reselect: https://github.com/faassen/reselect. It provides functionality similar to NuclearJS getters.

owais commented 9 years ago

@gaearon Cool! Great talk at ReactEurope BTW! Thanks.

gajus commented 9 years ago

This is my attempt to use Immutable.js with redux 1.0.0, https://github.com/gajus/redux-immutable

chiplay commented 9 years ago

Nice @gajus! Testing out redux-immutable now and really liking the https://github.com/gajus/canonical-reducer-composition pattern

gajus commented 9 years ago

Thank you @chiplay. I would really appreciate feedback should you come across deficiencies or have ideas for improvement.

jsifalda commented 9 years ago

is there any advantage of using immutable structures together with redux? when the redux is based on immutable behaviour (eg. stores return new copy of state)? Performance (any benchmarks?)? or something else? thx

gaearon commented 9 years ago

@jsifalda

Pros of using Immutable with Redux:

Cons of using Immutable with Redux:

The tradeoff is up to you!

jsifalda commented 9 years ago

@gaearon thank you very much for fast and helpful answer!

asaf commented 9 years ago

If you want ImmutableJs & Redux that conforms Redux standards you can take a look at https://github.com/indexiatech/redux-immutablejs,

@gaearon Is it possible to put a link on the web site ?

gajus commented 9 years ago

Thank you Asaf. I am sure people will find it useful.

On Sep 4, 2015, at 18:36, Asaf Shakarchi notifications@github.com wrote:

If you want ImmutableJs & Redux that conforms Redux standards you can take a look at https://github.com/indexiatech/redux-immutablejs,

@gaearon Is it possible to put a link on the web site ?

— Reply to this email directly or view it on GitHub.

gaearon commented 9 years ago

@asaf

Good stuff, would you like to make a PR to Ecosystem.md? I will happily add it there if you add tests to your project.

asaf commented 9 years ago

@gaearon Done with unit tests, PR is: https://github.com/rackt/redux/pull/707

Thanks!

websilone commented 8 years ago

Hi all, a little question for @gaearon, from the quick tests I've done so far to implement ImmutableJS on my existing React / Redux app, it feels a little slower :-/ but perhaps am I doing something in a wrong way...

Basic use case : getting a collection of data from an API call and storing it in a reducer...

From my reducer, Without ImmutableJS :

const initialStore = {
    isLoading : false,
    error     : null,
    data      : []
}

// in the switch case
return {
   ...state,
   isLoading: false,
   error: null,
   data: action.result
}

With ImmutableJS

const initialStore = Map({
    isLoading : false,
    error     : null,
    data      : List()
})

// in the handler function
return state.merge({
    isLoading: false,
    error: null,
    data: List(result.result)
})

I am wondering if the "treatment" ImmutableJS is doing isn't costing more here ?

From what I understand from Immutability, the benefit is more when the rendering quicks in, right ?

Thanks for your feedback.

gaearon commented 8 years ago

The benefit is that operating on large arrays and objects costs less memory and works faster. It doesn't make a large difference in small applications.

websilone commented 8 years ago

Ok, thanks. So I've got the right approach anyway ?

gaearon commented 8 years ago

Yeah, looks good to me.

piq9117 commented 7 years ago

So far the trade off has been worth it.. 💯