Anthony Dugois Anthony Dugois - 3 months ago 15
React JSX Question

React-redux rerenders when creating arrays

I have a connected component where I would like to retrieve an array of objects. In my store, there is an array of ids, and an object where I keep the items like this:

const state = {
items: [0, 1, 2],
itemsById: {
0: {},
1: {},
2: {},
},
}


So using the
connect
function of react-redux, I do this in my component to inject the correct array:

const mapStateToProps = (state) => ({
items: state.items.map((itemId) => state.itemsById[itemId]),
})


My app triggers updates very often (I dispatch actions in
requestAnimationFrame
), but the
items
array do not change during the process. By analyzing the app with the React Perf addon, it seems that my connected component makes unnecessary rendering, and I don't understand why because the
items
in the state don't change.

I already tried to make a memoized selector using reselect but it seems it does not change anything.

Update (solution)



It works when you use a selector created with reselect. My problem was in the selector itself: my
items
array is located in a parent object which updates very frequently, and I was selecting this object instead of selecting the
items
array directly.

Don't do this:

const parentSelector = (state) => state.parent
const itemsByIdSelector = (state) => state.itemsById
const selector = createSelector(
parentSelector,
itemsByIdSelector,
(parent, itemsById) => parent.items.map(...)
)


Do this:

const itemsSelector = (state) => state.items
const itemsByIdSelector = (state) => state.itemsById
const selector = createSelector(
itemsSelector,
itemsByIdSelector,
(items, itemsById) => items.map(...)
)

Answer

You are creating a new array every time connect is called by doing this:

const mapStateToProps = (state) => ({
  items: state.items.map((itemId) => state.itemsById[itemId]),
})

To prevent that use a memoized selector, which will return the same array every time, unless something actually changed. A selector is method that computes the derived data from the state. Reselect is a memoized selector library for redux.