Gar*_*ary 4 javascript reactjs
我遇到了这个答案,它似乎解决了这个问题:React何时重新渲染子组件?
但我在这里问一个更微妙的问题。为什么 React 在使用useMemohook 时(通常)会重新渲染子组件?
在下面的示例中,我希望Child和Mchild组件都不会在输入 onChange 事件上重新渲染,但只是Mchild不会重新渲染。Child每次按键时都会呈现。
有人能解释一下为什么 React 会这样做吗?我想我要问的是,我不明白为什么 React 默认不这样做。使用始终使用的子组件模式有什么缺点React.memo?
import React, { useMemo, useState } from "react";
const Child = ({ person, which }: any) => {
console.log(`${which} render`);
return <div>{`From child component: ${person.first}`}</div>;
};
const Mchild = React.memo(Child);
function Parent() {
console.log("Parent render");
const [message, setMessage] = useState<string>("");
const person = { first: "gary", last: "johnson" };
const mPerson = useMemo(() => person, []);
return (
<div>
<div>
MESSAGE:{" "}
<input value={message} onChange={(e) => setMessage(e.target.value)} />
</div>
<div>Parent</div>
<Child person={mPerson} which="Child" />
<Mchild person={mPerson} which="Mchild" />
</div>
);
}
export default Parent;
Run Code Online (Sandbox Code Playgroud)
当组件的内部状态发生变化或其父组件重新渲染时,组件将重新渲染。默认情况下,React 不会记住所有内容,因为首先,大多数重新渲染都不是扩展性的,其次,为了能够记忆,您需要一个比较算法,而该算法不是免费的,正如维护者之一Dan Abramov所说:
\n\n\n浅层比较是免费的。它们\xe2\x80\x99re O(prop count)。他们只会在企业纾困的情况下购买一些东西。我们最终重新渲染的所有比较都被浪费了。
\n为什么你总是期望比较速度更快?考虑到许多组件总是会获得不同的道具。
\n
// Default rendering behavior overview \n\nconst SimpleChild = () => {\n console.log("SimpleChild render");\n return <div></div>;\n};\n\nfunction Parent() {\n const [state, setState] = React.useState(true);\n console.clear();\n console.log("Parent render");\n return (\n <div>\n <p>Default rendering behavior overview </p>\n <SimpleChild />\n <button onClick={() => setState((prev) => !prev)}>Render Parent</button>\n </div>\n );\n}\n\nReactDOM.render(\n <Parent />,\n document.getElementById("root")\n);Run Code Online (Sandbox Code Playgroud)\r\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>\n<div id="root"></div>Run Code Online (Sandbox Code Playgroud)\r\n如果该子组件执行大量计算任务而不受父组件重新渲染的影响,则由于其父组件重新渲染而导致的组件重新渲染可能会出现问题。在这种情况下,您可以告诉 React 在父级重新渲染时不要重新渲染该子级,方法是memo:
// Memoizing with memo\n\nconst HeavyChild = React.memo(() => {\n console.log("HeavyChild render");\n return <div></div>;\n});\n\nfunction Parent() {\n const [state, setState] = React.useState(true);\n console.clear();\n console.log("Parent render");\n return (\n <div>\n <p>Memoizing with memo</p>\n <HeavyChild />\n <button onClick={() => setState((prev) => !prev)}>Render Parent</button>\n </div>\n );\n}\n\nReactDOM.render(\n <Parent />,\n document.getElementById("root")\n);Run Code Online (Sandbox Code Playgroud)\r\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>\n<div id="root"></div>Run Code Online (Sandbox Code Playgroud)\r\n现在,如果我们将一个对象传递给上面的 memoized 会发生什么HeavyChild?好吧,我们memo不会再做我们想做的事了。这是因为memo“类似”:
if (prevPropsValue === currentPropsValue) { \n // Don not re-render\n}\nRun Code Online (Sandbox Code Playgroud)\n但是在每次重新渲染时,父级中定义的对象都会在新引用上重新创建,因此它是一个新值。
\n// Memoizing with memo when an object is passed as props\n\nconst HeavyChild = React.memo(() => {\n console.log("HeavyChild render");\n return <div></div>;\n});\n\nfunction Parent() {\n const [state, setState] = React.useState(true);\n const someObject = {}\n console.clear();\n console.log("Parent render");\n return (\n <div>\n <p>Memoizing with memo when an object is passed as props</p>\n <HeavyChild someObject={someObject} />\n <button onClick={() => setState((prev) => !prev)}>Render Parent</button>\n </div>\n );\n}\n\nReactDOM.render(\n <Parent />,\n document.getElementById("root")\n);Run Code Online (Sandbox Code Playgroud)\r\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>\n<div id="root"></div>Run Code Online (Sandbox Code Playgroud)\r\n如果您想在将对象作为 props 传递时避免上述行为,您可以使用useMemo, 来记忆该对象:
\n\n当函数作为 props 传递时,我们有与对象相同的行为,在这种情况下我们用来
\nuseCallback记忆它们。
// Memoizing with memo when a memoized object is passed as props\n\nconst HeavyChild = React.memo(() => {\n console.log("HeavyChild render");\n return <div></div>;\n});\n\nfunction Parent() {\n const [state, setState] = React.useState(true);\n const someMemoizedObject = React.useMemo(()=>{}, [])\n console.clear();\n console.log("Parent render");\n return (\n <div>\n <p>Memoizing with memo when a memoized object is passed as props</p>\n <HeavyChild someMemoizedObject={someMemoizedObject} />\n <button onClick={() => setState((prev) => !prev)}>Render Parent</button>\n </div>\n );\n}\n\nReactDOM.render(\n <Parent />,\n document.getElementById("root")\n);Run Code Online (Sandbox Code Playgroud)\r\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>\n<div id="root"></div>Run Code Online (Sandbox Code Playgroud)\r\n最后要知道的是,如果包装一个可以使用的子组件(就像在本例中一样),到目前为止,它始终是一个新引用,则不会memo按预期工作。HeavyChildchildrenchildren
// Memoizing with memo when a component is passed as children\n\nconst SomeNestedChild = () => {\n return <div></div>;\n};\n\nconst HeavyChild = React.memo(({children}) => {\n console.log("HeavyChild render");\n return <div></div>;\n});\n\nfunction Parent() {\n const [state, setState] = React.useState(true);\n \n console.clear();\n console.log("Parent render");\n \n return (\n <div>\n <p>Memoizing with memo when a component is passed as children</p>\n <HeavyChild><SomeNestedChild/></HeavyChild>\n <button onClick={() => setState((prev) => !prev)}>Render Parent</button>\n </div>\n );\n}\n\nReactDOM.render(\n <Parent />,\n document.getElementById("root")\n);Run Code Online (Sandbox Code Playgroud)\r\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>\n<div id="root"></div>Run Code Online (Sandbox Code Playgroud)\r\n