angular-redux / ng-redux

Angular bindings for Redux
MIT License
1.16k stars 177 forks source link

question: ng-redux and immutable #101

Open ipassynk opened 8 years ago

ipassynk commented 8 years ago

I am using ng-redux with angular 1 application and my store does not use immutable.js at this moment. I am wondering how to make the store immutable and do affect the performance with toJS calls in the controller. I especially concert with calling toJS on each store update in mapStateToProps function. I saw the in react community people use reselect to solve similar concerns. I am wondering if reselect can be also used with ng-redux?

As alternative I am currently playing with idea to use _.memoize in my mapToState function to check if specific slice on store in immutable store has been changed. I am wondering if somebody already use immutable.js with angular 1 and how?

//Let say i have the following store 
let state = Immutable.fromJS({categories: {1: 'a',2: 'b'},links: [1,2,3]});

// my component has binding only to categories sub-store in html view
let key = 'categories';

// mapStateTpProp will call toJS ONLY then category has been changed.
let shouldBindingUpdate = _.memoize((sliceObj, fn) => fn());
function mapStateTpProp(state) {
 return shouldBindingUpdate(state.get(key), () => {
   console.log('toJS called');
   return state.getIn([key]).toJS()
 });
}

//  the first time mapStateTpProp is called and toJS is called
mapStateTpProp(state);

// links subtree has been changed and therefore toJS should not be called since the component cares only about 'categories'
state = state.setIn(['links', '1'], 10);
mapStateTpProp(state);

// reducer changes categories substate in the store and toJS should be called to update view
state = state.setIn(['categories', '1'], 'new Value');
mapStateTpProp(state);
wbuchwalter commented 8 years ago

Hey, I haven't used immutable.js personnaly (I was primarily using typescript, which doesn't plays well with immutable.js), so I can't really tell about performance issues. That said, Reselect can totally be used with ng-redux, I used it extensively. You use it the same way you would in React. Here is an old example (in Typescript). This other somewhat old example uses immutable.js.

Closing the issue, but let me know if that doesn't answer your questions. Thanks

ipassynk commented 8 years ago

Thanks. I see that reselect is used but i don't think the example app shows a way to use immutable in PROD application. Even the comment says : "For clarity of the examples, we are doing toJS/fromJS within the reducer so our component code is easier to follow, and only using immutableJS here to provide an easy way to do updates to our collection in an immutable fashion". It is too expensive to do toJS and fromJS in reducers and i am trying to find a way to use immutable and get best of immutable.js smart structural sharing and angular digest.

wbuchwalter commented 8 years ago

Why don't you do like what is done in react + redux? Considering that reselect works as well in angular than in react? I don't understand what's missing there.

Again, I have never used immutable.js in a prod application myself, so sorry for the dumb questions :)

ipassynk commented 8 years ago

As I see how react uses immutable with redux - they try not to perform toJS expensive operation but use immutable collection in JSX. Since all immutable collections are Iterable and have filter, map... API, you can use them directly in JSX without going though very expensive toJS operation that deeply copies the whole store to plain javascript. In immutable.js if a subtree has not been changed after setIn, merge operations, immutable.js will reuse the sub-tree in a new obj. By checking the old ref with new ref you can figure out if sub-tree has been changed (like angular 2 on Push detection) and go via render only when it is needed. If we use toJS - this is completely new object and we loose benefits of immutable and the app performance gets decreased.

wbuchwalter commented 8 years ago

Thanks for the clarification. Reopening this issue in case someone has some insights to share. Sorry for not being able to help you more on this one :)

jasonaden commented 8 years ago

@ipassynk Are you using selectors? Or reselect library? If so, just do the toJs in the selector. If you're using reselect, the toJs method will only run when there is a change to the data. So you can use immutable in your reducers but deal with POJOs in your app.

hangzho commented 7 years ago

Recently, I was playing around with ng-redux, immutable and reselect. I post the link here https://github.com/johanzhou8/ng-redux/tree/master/examples/async-immutable in case someone needs the example.