简体   繁体   中英

Deep Compare in Redux Reducer or in Component's ShouldComponentUpdate?

In my React Redux app, a setInterval() continuously calls an action creater this.props.getLatestNews() which queries a REST API endpoint. On getting the API response (an array of objects), it will dispatch an action with the response array as the payload.

React Component

class Newsfeed extends Component {
    constructor(props) {
        super(props);
        this.state = { ... }
    }

    componentWillMount() {
        this.updateTimer = setInterval(() => { this.props.getLatestNews() }, 1000);
    }

    componentWillUnmount() {
        clearInterval( this.updateTimer );
    }

    shouldComponentUpdate(nextProps, nextState) {
        // Should we do a deep compare of nextProps & this.props, 
        // shallow compare of nextState & thisState?
    }

    render() {
        return ( ... )
    }
}

const mapStateToProps = (state) => ({
    newsfeed: state.newsfeed
});

const mapDispatchToProps = (dispatch) => {
    return {
        getLatestNews: () => dispatch(getLatestNews())
    }
};

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

In the reducer, it currently always update part of the state, whether or not there is any changes

Reducer

export default function newsfeedReducer(state=initialState, action) {
    switch (action.type) {
        case NEWSFEED_RECEIVED:
            // Or should we do the deep compare of `action.payload` with `state.items` here?
            return { ...state, items: action.payload }

        default:
            return state
    }
}

Root Reducer

...

const rootReducer = combineReducers({
    newsfeed: newsfeedReducer
});

...

Most of the time, when the API results are received, there are no new items that do not already exist in the Redux store. If the reducer still replaces this part of the store with the API results, the connected component will re-render due to the new object reference to props unless we do a deep comparison inside shouldComponentUpdate() .

In order to avoid unnecessary re-rendering of the React Components, I was thinking of either performing a deep compare of the current and next props in the shouldComponentMount() function, or doing the deep compare of the action.payload with state.items that it should replace.

Where is the recommended location to perform the deep comparison? Or is this unnecessary at all?

Thank you!

In general, there are few choices we can make to avoid re-rendering when using redux.

  1. In Reducer: Do comparison of current state and api/action payload results ie your would-be/next state. Just return previous state in your reducer to not cause re-render
  2. In component : If your comparison depends on your component prop then use shouldComponentUpdate which gives you nextProps and nextState as arguments.
  3. In Actions : If you want do conditional dispatching (ie if not happy with api-results then dispatch something else)then do the comparison in your actions. You can use getState to access the current state.

Note - Even if you use Pure component, the component will still re-render because the state's object reference is changed even if object values are same.

Demo of point 1 - shouldComponentUpdate

编辑 shouldcomponent 更新修复

Demo of point 2 - state-reducer-etc

编辑 react+redux+reducer+test

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM