Reputation: 256
I'm wondering what the best approach to handle this scenario is in redux and if theres any patterns to favour or avoid:
I have a 'shopping list' component that is comprised of several sub items, each of which can be modified in a variety of ways. I'm also keeping track of the total price of the shopping list which changes every time a sub item is added, removed or modified as well as other factors.
Currently I have a 'Total' component which is subscribed to the store and recalculates the total when any shopping list items (passed to it as props) change. This then saves the recalculated total to the store. Whilst this works and is seemingly more robust than trying to anticipate every action that has an effect on the total, it does mean that the app re-renders twice: firstly when an item changes, then secondly when the total is recalculated.
I'm presuming that this is probably not the best approach to the situation and I'm wondering if I can do something a bit neater directly in the shopping list reducer or using some kind of middleware. Any advice would be appreciated.
-
The current process can be summarised as:
Upvotes: 2
Views: 5688
Reputation: 2223
The fact that you're using the Total component to calculate the total and then dispatch an action to update the total in the store is what's complicating things. Your total is actually just a derivation of other parts of your state, and does not need to be stored in the state itself.
Assuming you're using react-redux to connect your Total component to your state, you can simply calculate the total in the mapStateToProps part of your connect(). For example:
const mapStateToProps = (state, props) => {
return {
total: state.shoppingList.reduce((total, item) => total + item.price, 0)
}
}
export default connect(mapStateToProps)(Total)
(This example assumes state.shoppingList
is an array of items, each with a price
property. Your situation is probably a little more complex, but the idea is the same.)
This would allow your Total component to access/display the total, but without any of the added complication of having to re-update the state.
For improved performance in these state derivations, have a look at reselect. It allows you to create "memoized" selectors that will only perform their re-calculations when the relevant parts of state have changed, otherwise they will return the derived value from memory. These selectors can be imported anywhere, so it would make it easy to display the total in other places too, if you ever needed to.
Upvotes: 3
Reputation: 78
If i understand correctly i think you should use the component will update function :
void componentWillReceiveProps(
object nextProps
)
Quote from the official doc :
"Invoked when a component is receiving new props. This method is not called for the initial render.
Use this as an opportunity to react to a prop transition before render() is called by updating the state using this.setState(). The old props can be accessed via this.props. Calling this.setState() within this function will not trigger an additional render."
This means that when a modification is made to your shopping list, you can calculate the total in the componentWillReceiveProps function without triggering a second render.
Upvotes: 0