1ven
1ven

Reputation: 7016

Component is updating when previous props are equal to the next props

In simple todo list application, I have FiltersContainer component, which provides props to Filters component:

// FiltersContainer.js
import { connect } from 'react-redux';
import { setVisibilityFilter } from '../actions';
import Filters from '../components/Filters';

function mapStateToProps(state) {
  const { visibilityFilter } = state.todos;

  // `visibilityFilter` variable value is - 'SHOW_ALL'.
  return {
    filters: [{
      title: 'All',
      value: 'SHOW_ALL',
      active: visibilityFilter === 'SHOW_ALL',
    }, {
      title: 'Completed',
      value: 'SHOW_COMPLETED',
      active: visibilityFilter === 'SHOW_COMPLETED',
    }, {
      title: 'Active',
      value: 'SHOW_ACTIVE',
      active: visibilityFilter === 'SHOW_ACTIVE',
    }],
  };
}

function mapDispatchToProps(dispatch) {
  return {
    onFilterClick(value) {
      dispatch(setVisibilityFilter(value));
    },
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(Filters);

The problem is, that this component renders everytime state changes.

For example, toggling todo item forces rendering <Filters /> component, although filters array and visibilityFilter hasn't changed.


If replace filters array in mapStateToProps function with string, this component would not be rendering on every state changes:

// FiltersContainer.js
function mapStateToProps(state) {
  const { visibilityFilter } = state.todos;

  return {
    filters: '',
  };
}

Full application code is available at - https://github.com/1ven/react-redux-todos

Am I missing something?

Upvotes: 1

Views: 1100

Answers (2)

1ven
1ven

Reputation: 7016

The problem was in shallowEqual util function, which uses react-redux library to check whether component props changed.

This function does not makes deepEqual checking, it only makes shallow checking, thats why object, which contains property with array is not equal to the same object.

Upvotes: 0

Piyush.kapoor
Piyush.kapoor

Reputation: 6803

EveryTime you are returning a new Object from mapStateToProps thats why old props are not equal to the new props. Hence the component gets rendered everytime

React render the component if old props are not equal to new props In your case you do

 return {
    filters: [{
      title: 'All',
      value: 'SHOW_ALL',
      active: visibilityFilter === 'SHOW_ALL',
    }, {
      title: 'Completed',
      value: 'SHOW_COMPLETED',
      active: visibilityFilter === 'SHOW_COMPLETED',
    }, {
      title: 'Active',
      value: 'SHOW_ACTIVE',
      active: visibilityFilter === 'SHOW_ACTIVE',
    }],
  };

oldProps = object

newProps = another object (although content is same both are different objects )

oldprops==newprops //no rerender

When you do

return {
    filters: '',
  };

oldprops = ''; newprops = '' oldprops === newprops dont render

Upvotes: 1

Related Questions