React组件已设key仍不渲染?Redux项目渲染异常求助
Hey there! Let's dig into why your Product component isn't re-rendering after updating the cart, and walk through a stable fix that avoids hacky workarounds.
What's Causing the Problem?
React decides whether to re-render a component by doing a shallow comparison of its props and state. Here's what was likely happening in your case:
- Redux State Mutation: If your reducer for
ADD_PRODUCTS_TO_CARTwas modifying the existing product object directly (instead of returning a new copy of the object with updated stock), the reference to theobjyou're passing toProductstayed the same. - Prop Comparison: When you passed the entire
objas adataprop toProduct, React saw that the prop's reference hadn't changed—even though theStockvalue inside it had. Since React does a shallow check, it assumed the prop was the same and skipped re-renderingProduct.
Your temporary fixes worked for these reasons:
- Changing the key to include
Stockforced React to treat the component as a new instance (unmounting and remounting it), which is why it re-rendered. But this is a hack—unmounting components can lose internal state and hurt performance. - Splitting
data={obj}into individual props (likestock={obj.Stock}) worked because primitive values (numbers, strings) are compared by value. WhenStockchanged, React saw the prop value was different and triggered a re-render.
Stable Solutions
Let's fix this properly, starting with the root cause in your Redux reducer, then optimizing your component props.
1. Ensure Your Reducer Returns New State (Critical!)
Redux reducers must be pure functions—never mutate the existing state. Always return new copies of objects/arrays when updating state. For your ADD_PRODUCTS_TO_CART case, update the product like this:
case 'ADD_PRODUCTS_TO_CART': return { ...state, // Map over products to create a new array products: state.products.map(product => { if (product.ID === action.payload.id) { // Return a NEW object with updated stock—don't modify the original! return { ...product, Stock: product.Stock - action.payload.quantity }; } // Return unchanged products as-is return product; }) };
This ensures that any product with updated stock gets a new object reference. Now when you pass data={obj} to Product, React will detect the reference change and trigger a re-render.
2. Optimize Product Component Updates
Even with correct state updates, you can make your components more efficient:
- Keep using individual props (recommended): Passing primitive values like
id={obj.ID},stock={obj.Stock}makes React's shallow comparison straightforward and reliable. It also makes your component's dependencies clearer. - Use
React.memofor functional components: If you prefer passing the entire product object, wrap yourProductcomponent inReact.memoto add a custom comparison check. This tells React to re-render only when specific properties change:
const Product = React.memo(({ data }) => { // Your component render logic here }, (prevProps, nextProps) => { // Re-render only if ID or Stock changes return ( prevProps.data.ID === nextProps.data.ID && prevProps.data.Stock === nextProps.data.Stock ); });
This prevents unnecessary re-renders while ensuring the component updates when critical values like stock change.
Final Notes
The core issue was a combination of improper state mutation in Redux and React's shallow prop comparison. By fixing your reducer to return new state objects, you'll ensure React can detect changes correctly. Pairing this with either individual props or React.memo gives you a stable, performant solution—no hacky key changes needed.
内容的提问来源于stack exchange,提问作者Kristian Daugaard

