Is it okay to connect a PureComponent?

Actually connect() function makes the wrapped component pure by default (see docs). That is, the wrapped component will be rerendered only when the properties change (state or own props). So there's no point in inheriting from PureComponent, because shouldComponentUpdate logic is already implemented in HOC produced by connect().

I've heard that PureComponents can slow down performance...

Shallow props comparison performed by PureComponent is relatively cheap operation. I don't think it's going to be an issue.


There is no issue in using connect and PureComponent. PureComponent renders if the props have changed and connect() maps the redux state to props. See in this example by the redux team. I have replaced the TodoList component with a Purecomponent:

class TodoList extends React.PureComponent {
  render() {
    const { todos, toggleTodo } = this.props;
    return (
      <ul>
        {todos.map(todo => (
          <Todo key={todo.id} {...todo} onClick={() => toggleTodo(todo.id)} />
        ))}
      </ul>
    );
  }
}

/*
const TodoList = ({ todos, toggleTodo }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => toggleTodo(todo.id)}
      />
    )}
  </ul>
)
*/

It works just the same.


I had a problem with list items that were connected components and ended up here after googling for it.

I will add the description of the problem and my solution here:

The mapStateToProps looks something like this

import { defaultMemoize } from 'reselect';

const mapStateToProps = () => {
  const createMergedItem = defaultMemoize((item, edit) =>
    edit
      ? { ...item, edit: true }
      : { ...item, edit: false }
  );
  return (state, { item, edits }) => {
    //returning same ref when item and edits[item.id] didn't change
    return createMergedItem(item, Boolean(edits[item.id]));
  };
};

export default connect(
  mapStateToProps,
)(Item);

In the List component

items.map(item=>(<Item key={item.id} item={item} edit={edit} />)

The code is a bit simplified but what it does is that List passes an item and edit to each Item component as props, edit is an object that has members with an item.id as key. If I have an item with id 1 and edits is {1:anythingTruthy} then the item 1 is in edit mode.

When I'd change an item in the list from or to edit mode then all the items in the list that weren't in changed would re render even though mapStateToProps would return the same reference as last time.

I always thought that connect would return a pure component but I was mistaken, the solution is to make Item a pure component and with React.memo this is very simple:

import { memo } from 'react';
//mapStateToProps is the same
export default connect(
  mapStateToProps,
)(memo(Item));//wrap Item in memo

Where Item is a functional component (props=>jsx).

when you change edit mode of one item in the list the edit prop will change for all items but thanks to defaultMemoize and returning a function from mapStateToProps that crates a memoized createMergedItem function it'll return props that has the same reference as the last one. This was not enough because the Item function was still called. I had to also use React.memo to make Item a pure component.