admin管理员组文章数量:1193758
const initialState = {
productEditor: {
productDetails: {
id: 1,
name: "Product A",
description: "A great product",
},
tags: ["tag1", "tag2"],
images: {
main: "image1.png",
gallery: ["image2.png", "image3.png"],
},
},
};
Using React-Redux selectors suppose one component subscribes to productDetails.name
and another subscribes to images.main
but I change productDetails.name
, will this cause other components to re-render? Is it possible to divide a state into categories and only subscribe to any depth property avoiding unnecessary re-renders? As I understand, Redux compares references so if I just reassign an existing object its ref wont change so that should not cause re-render.
const initialState = {
productEditor: {
productDetails: {
id: 1,
name: "Product A",
description: "A great product",
},
tags: ["tag1", "tag2"],
images: {
main: "image1.png",
gallery: ["image2.png", "image3.png"],
},
},
};
Using React-Redux selectors suppose one component subscribes to productDetails.name
and another subscribes to images.main
but I change productDetails.name
, will this cause other components to re-render? Is it possible to divide a state into categories and only subscribe to any depth property avoiding unnecessary re-renders? As I understand, Redux compares references so if I just reassign an existing object its ref wont change so that should not cause re-render.
1 Answer
Reset to default 0Using React-Redux selectors suppose one component subscribes to
productDetails.name
and another subscribes toimages.main
but I changeproductDetails.name
will this cause other components to re-render?
No, only when what the useSelector
hook is selecting changes does this trigger the subscribed component to rerender. In other words, components only rerender when what they are subscribed to changes. If one component is subscribed to productDetails.name
and another is subscribed to images.main
, then state updates specifically to productDetails.name
does not trigger the component subscribed to images.main
to rerender, and vice-versa.
Demo
Consider this demo sandbox:
Demo Code:
index.js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import App from "./App";
import { store } from "./store";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>
);
store.js
import { configureStore } from "@reduxjs/toolkit";
import stateReducer from "./state.slice";
export const store = configureStore({
reducer: stateReducer,
});
state.slice.js
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
productEditor: {
productDetails: {
id: 1,
name: "Product A",
description: "A great product",
},
tags: ["tag1", "tag2"],
images: {
main: "image1.png",
gallery: ["image2.png", "image3.png"],
},
},
};
const stateSlice = createSlice({
name: "state",
initialState,
reducers: {
updateProductName: (state, action) => {
state.productEditor.productDetails.name = action.payload;
},
updateImagesMain: (state, action) => {
state.productEditor.images.main = action.payload;
},
},
});
export const { updateImagesMain, updateProductName } = stateSlice.actions;
export default stateSlice.reducer;
App.js
import { useEffect, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import { nanoid } from "@reduxjs/toolkit";
import { updateImagesMain, updateProductName } from "./state.slice";
const ComponentA = () => {
const dispatch = useDispatch();
const productDetails = useSelector(
(state) => state.productEditor.productDetails
);
const renderCount = useRef(0);
useEffect(() => {
console.log("ComponentA RENDERED");
renderCount.current++;
});
return (
<div>
<h1>Product Details</h1>
<button
type="button"
onClick={() => dispatch(updateProductName(nanoid()))}
>
Update Product Name
</button>
<p>{JSON.stringify(productDetails)}</p>
<p>Render Count: {renderCount.current}</p>
</div>
);
};
const ComponentB = () => {
const dispatch = useDispatch();
const images = useSelector((state) => state.productEditor.images);
const renderCount = useRef(0);
useEffect(() => {
console.log("ComponentB RENDERED");
renderCount.current++;
});
return (
<div>
<h1>Images</h1>
<button
type="button"
onClick={() => dispatch(updateImagesMain(nanoid()))}
>
Update Images Main
</button>
<p>{JSON.stringify(images)}</p>
<p>Render Count: {renderCount.current}</p>
</div>
);
};
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<ComponentA />
<ComponentB />
</div>
);
}
Note
Because of the way React-Redux is optimized via the useSelector
hook you'll want to be as granular and specific as to the state values you are selecting. Selecting more than you actually need may trigger unnecessary component re-renders. For example, if both components subscribed to state.productEditor
instead of the more deeply nested states, then any time state.productEditor.productDetails.*
or state.productEditor.images.*
updated, both subscribers would re-render.
const { productDetails } = useSelector(state => state.productEditor);
const { images } = useSelector(state => state.productEditor);
Updates to anything in state.productEditor
will cause both these susbcribers to re-render.
本文标签:
版权声明:本文标题:javascript - Will updating a single property in a deeply nested react Redux state cause re-renders for all components that subsc 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738417610a2085674.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论