Limit Redux to update only components affected by the change

Zalaboza picture Zalaboza · Aug 9, 2016 · Viewed 7.1k times · Source

trying to understand React-Redux, i find it unusual that all my components get new props when ever any slice of the state get changed. so is this by design or i'm doing something wrong ?

example App

class App extends React.Component {

  render(){return (
          <div> 
            <Navbar data={this.props.navbar} />
            <Content data={this.props.content} />
          </div>);
  }

}
select (state) => ({ navbar:state.navbar, content:state.content});
export default connect(select)(App);

Components

export const NavbarForm = props => {
  console.log('RENDERING with props--->',props);
  return (<h1>NAV {props.data.val}</h1>);
};
export const ContentForm = props => {
  console.log('RENDERING CONTENT with props--->',props);
  return (<h1>CONTENT {props.data.val}</h1>);
};

////////INDEX.js//////

const placeholderReducer = (state={val:0},action)=>{
//will update val to current time if action start with test/;
if(action.type.indexOf('TEST/') === 0)return {val:Date.now();}

return state;
}

export const rootReducer = combineReducers({
  navbar:placeholderReducer,
  content: (state,action)=>(state || {}), //**this will never do a thing.. so content should never updates right !!**
});

const store = createStore(rootReducer, {}, applyMiddleware(thunk));

render( <Provider store={store}> <App /></Provider>, document.getElementById('app')
);
setInterval(()=>{  store.dispatch(()=>{type:'TEST/BOOM'})  },3000);

okay in this app, what i expect is that Navbar component will get updated every 3000ms while content component will never updates because its reducer will always return the same state.

yet i find it really strange that both components does reRender every time an action is fired.

is this by design ? should i worry about performance if my app has 100+ component ?

Answer

markerikson picture markerikson · Aug 9, 2016

This is entirely by design. React assumes that your entire app will be re-rendered from the top down by default, or at least a given subtree will be re-rendered if a certain component does a setState or something similar.

Because you only have the very top component in your app connected, everything from there on down is React's standard behavior. A parent component re-renders, causing all of its children to re-render, causing all of their children to re-render, and so on down.

The core approach to improving UI performance in React is to use the shouldComponentUpdate lifecycle method to check incoming props and return false if the component does not need to re-render. This will cause React to skip re-rendering that component and all of its descendants. Comparisons in shouldComponentUpdate are generally done using shallow reference equality, which is where the "same object references means don't update" thing becomes useful.

When using Redux and connect, you will almost always find yourself using connect on many different components in your UI. This provides a number of benefits. Components can individually extract the pieces of the store state that they need, rather than having to hand them all down from the root component. In addition, connect implements a default shouldComponentUpdate for you, and does a similar check on the values you return from your mapStateToProps function. So, in a sense, using connect on multiple components tends to give you a "free win" in regards to performance.

Further reading on the topic: