When to use .toJS() with Immutable.js and Flux?

后端 未结 5 640
礼貌的吻别
礼貌的吻别 2021-01-30 16:38

I\'m trying to use ImmutableJS with my React / Flux application.

My stores are Immutable.Map objects.

I\'m wondering at which point should I use

5条回答
  •  逝去的感伤
    2021-01-30 17:26

    Kinda old question but lately I've been experimenting with this approach using reselect and lodash's memoize in the effort of returning comparable objects to React's Components.

    Imagine you have a store like this:

    import { List, Map } from 'immutable';
    import { createSelector } from 'reselect';
    import _ from 'lodash'; 
    
    const store = {
        todos: List.of(
            Map({ id: 1, text: 'wake up', completed: false }), 
            Map({ id: 2, text: 'breakfast', completed: false })
        )
    };
    
    const todosSelector = state => state.todos;
    
    function normalizeTodo(todo) {
        // ... do someting with todo
        return todo.toJS();
    }
    
    const memoizeTodo = _.memoize(normalizeTodo);
    
    export const getTodos = createSelector(
        todosSelector,
        todos => todos.map(memoizeTodo)
    );
    

    Then I pass to a TodoList component todos as a prop, which will then be mapped into two TodoItem Components:

    class TodoList extends React.Component {
        shouldComponentUpdate(nextProps) {
             return this.props.todos !== nextProps.todos;
        }
    
        render() {
           return (
    {this.props.todos.map(todo => )}
    ); } } class TodoItem extends React.Component { shouldComponentUpdate(nextProps) { return this.props.todo !== nextProps.todo; } // ... }

    This way, if nothing changed in the todo's store, when I call getTodos() reselect returns to me the same object, and so nothing gets re-rendered.

    If, for example, todo with id 2 is marked as completed, it also changes in the store, and so a new object is returned by todosSelector. Then the todos are mapped by memoizeTodo function, which should return the same object if a todo isn't changed (since they are Immutable Maps). So when TodoList receives the new props, it re-renders because todos has changed, but only the second TodoItem re-renders because the object representing the todo with id 1 didn't change.

    This surely could lead to a performance loss, especially if our store contains a lot of items, but I didn't notice any problem in my medium-size app. The upside of this approach is that your Components receives plain javascript objects as props and could use them with something like PureRenderMixin, so how objects are returned from the store is not business of Components anymore.

提交回复
热议问题