According to the redux FAQ from here https://github.com/reduxjs/redux/blob/master/docs/recipes/UsingImmutableJS.md#what-are-some-opinionated-best-practices-for-using-immutable-js-with-redux:
"Your selectors should return Immutable.JS objects". "Always".
Why is this the case?
As a disclaimer, this isn't "always" the case, but the docs are trying to point you in the right direction for most cases.
Since reselect memoizes the return result of selectors, returning a mutable object leaves you susceptible to tricky bugs. Imagine the following scenario:
// Immutable State
{
todos: [{ text: "hey"}, { todo: "text"}]
}
// Selectors
const getTodos = createSelector(state => state.todos, immutableTodos => immutableTodos.toJS())
The getTodos
selector is returning a plain JS object, which by default is mutable. Now imagine multiple smart components that are using the getTodos
selector.
class EditTodos extends PureComponent {
constructor(props) {
this.state = { todos: props.todos }
}
addUnsavedTodo(newTodo) {
// Accidentally mutate the return result of getTodos
const newTodos = this.state.todos.push(newTodo)
this.setState({ todos: newTodos })
}
render() { // Some components for adding unsaved todos }
}
const mapStateToProps = (state) => ({ todos: getTodos(state))
A second component also using getTodos
would see the new "unsaved" todo as soon as addUnsavedTodo
is called, which would most likely be unintentional. All calls to getTodos
, assuming redux state
is unchanged, will get the same reference and any mutations will affect all consumers.
The example above is contrived, but hopefully it demonstrates one of the reasons that returning plain JS objects can be risky.
Furthermore, as the docs mention, you should limit your use of toJS
since it has performance implications. There is no benefit to converting your immutable object into a plain JS object within a selector