Child re-rendering 因为函数?
Child re-rendering because of function?
在 child 保留 re-rendering 的地方,我无法理解这些概念,因为我正在向它传递来自 parent 的函数。这个 parent 函数引用了编辑器的值 draftjs。
function Parent() {
const [doSomethingValue, setDoSomethingValue] = React.useState("");
const [editorState, setEditorState] = React.useState(
EditorState.createEmpty()
);
const editorRef = useRef<HTMLInputElement>(null);
const doSomething = () => {
// get draftjs editor current value and make a fetch call
let userResponse = editorState.getCurrentContent().getPlainText("\u0001");
// do something with userResponse
setDoSomethingValue(someValue);
}
return (
<React.Fragment>
<Child doSomething={doSomething} />
<Editor
ref={editorRef}
editorState={editorState}
onChange={setEditorState}
placeholder="Start writing..." />
<AnotherChild doSomethingValue={doSomethingValue}
<React.Fragment>
}
}
我的 Child 组件只是一个调用 parent 的 doSomething 的按钮,仅此而已。
doSomething 做它的事情然后改变状态然后传递给另一个Child。
我的问题是,每当 editorState 更新时(即每次您在编辑器中键入时),我的 Child 组件 re-renders。那不是没有必要吗?如果是这样,我该如何避免呢?
如果我向 Child 组件传递一个字符串并利用 React.Memo,它不会 re-render 除非字符串发生变化。
那么我在将函数传递给 child 时遗漏了什么? 我的child应该每次都是re-rendering吗?
如果您不希望每次重新渲染您的父组件时都重新渲染您的组件,您应该看看 useMemo
。
这个函数只会在它的第二个参数发生变化时重新计算它的值(在你的例子中,你的组件)(这里,它唯一依赖的东西,doSomething()
)。
function Parent() {
const [editorState, setEditorState] = React.useState(
EditorState.createEmpty()
);
const editorRef = useRef<HTMLInputElement>(null);
const doSomething = () => {
// get draftjs editor current value and make a fetch call
let userResponse = editorState.getCurrentContent().getPlainText("\u0001");
// do something with userResponse
}
const childComp = useMemo(() => <Child doSomething={doSomething} />, [doSomething])
return (
<React.Fragment>
{childComp}
<Editor
ref={editorRef}
editorState={editorState}
onChange={setEditorState}
placeholder="Start writing..." />
<React.Fragment>
}
}
如果 doSomething
没有改变,您的组件不会重新呈现。
如果您的函数正在进行繁重的计算,您可能还想为您的函数使用 useCallback
,以避免每次组件渲染时都重新编译它:https://reactjs.org/docs/hooks-reference.html#usecallback
查看 PureComponent
、useMemo
或 shouldComponentUpdate
我还要补充一点,不是传递函数来渲染顶级组件,而是传递值并稍后在组件树中定义函数。
如果你想避免不必要的重新渲染,你可以使用 React.memo 和钩子 useCallback。看看下面的sandbox。
button1 总是被重新渲染,因为它接受了一个没有被 useCallback 记住的回调,而 button2 只是第一次渲染,即使父级的状态已经改变(查看控制台以检查重新渲染) .您必须在负责呈现按钮的子组件中使用 React.memo。
希望对您有所帮助。
React 致力于参考变更检测以重新渲染组件。
Child.js
:将其包裹在React.memo so it becomes Pure Component.
下
const Child = ({doSomething}) => <button onClick={doSomething}>Child Button Name</button>;
export default React.memo(Child);
Parent.js -> doSomething
:在每次(重新)渲染时,也会重新创建回调。使用 useCallback 这样您的函数就不会在每次渲染时都重新创建。
const doSomething = React.useCallback(() => {
let userResponse = editorState.getCurrentContent().getPlainText("\u0001");
setDoSomethingValue(someValue);
}, [editorState]);
旁注
更广泛地说,memo
是 HOC 并且使组件成为纯组件。 useMemo
是缓存函数输出的东西。而 useCallback
缓存函数的实例。
希望对您有所帮助。
在 child 保留 re-rendering 的地方,我无法理解这些概念,因为我正在向它传递来自 parent 的函数。这个 parent 函数引用了编辑器的值 draftjs。
function Parent() {
const [doSomethingValue, setDoSomethingValue] = React.useState("");
const [editorState, setEditorState] = React.useState(
EditorState.createEmpty()
);
const editorRef = useRef<HTMLInputElement>(null);
const doSomething = () => {
// get draftjs editor current value and make a fetch call
let userResponse = editorState.getCurrentContent().getPlainText("\u0001");
// do something with userResponse
setDoSomethingValue(someValue);
}
return (
<React.Fragment>
<Child doSomething={doSomething} />
<Editor
ref={editorRef}
editorState={editorState}
onChange={setEditorState}
placeholder="Start writing..." />
<AnotherChild doSomethingValue={doSomethingValue}
<React.Fragment>
}
}
我的 Child 组件只是一个调用 parent 的 doSomething 的按钮,仅此而已。
doSomething 做它的事情然后改变状态然后传递给另一个Child。
我的问题是,每当 editorState 更新时(即每次您在编辑器中键入时),我的 Child 组件 re-renders。那不是没有必要吗?如果是这样,我该如何避免呢?
如果我向 Child 组件传递一个字符串并利用 React.Memo,它不会 re-render 除非字符串发生变化。
那么我在将函数传递给 child 时遗漏了什么? 我的child应该每次都是re-rendering吗?
如果您不希望每次重新渲染您的父组件时都重新渲染您的组件,您应该看看 useMemo
。
这个函数只会在它的第二个参数发生变化时重新计算它的值(在你的例子中,你的组件)(这里,它唯一依赖的东西,doSomething()
)。
function Parent() {
const [editorState, setEditorState] = React.useState(
EditorState.createEmpty()
);
const editorRef = useRef<HTMLInputElement>(null);
const doSomething = () => {
// get draftjs editor current value and make a fetch call
let userResponse = editorState.getCurrentContent().getPlainText("\u0001");
// do something with userResponse
}
const childComp = useMemo(() => <Child doSomething={doSomething} />, [doSomething])
return (
<React.Fragment>
{childComp}
<Editor
ref={editorRef}
editorState={editorState}
onChange={setEditorState}
placeholder="Start writing..." />
<React.Fragment>
}
}
如果 doSomething
没有改变,您的组件不会重新呈现。
如果您的函数正在进行繁重的计算,您可能还想为您的函数使用 useCallback
,以避免每次组件渲染时都重新编译它:https://reactjs.org/docs/hooks-reference.html#usecallback
查看 PureComponent
、useMemo
或 shouldComponentUpdate
我还要补充一点,不是传递函数来渲染顶级组件,而是传递值并稍后在组件树中定义函数。
如果你想避免不必要的重新渲染,你可以使用 React.memo 和钩子 useCallback。看看下面的sandbox。 button1 总是被重新渲染,因为它接受了一个没有被 useCallback 记住的回调,而 button2 只是第一次渲染,即使父级的状态已经改变(查看控制台以检查重新渲染) .您必须在负责呈现按钮的子组件中使用 React.memo。
希望对您有所帮助。
React 致力于参考变更检测以重新渲染组件。
Child.js
:将其包裹在React.memo so it becomes Pure Component.
const Child = ({doSomething}) => <button onClick={doSomething}>Child Button Name</button>;
export default React.memo(Child);
Parent.js -> doSomething
:在每次(重新)渲染时,也会重新创建回调。使用 useCallback 这样您的函数就不会在每次渲染时都重新创建。
const doSomething = React.useCallback(() => {
let userResponse = editorState.getCurrentContent().getPlainText("\u0001");
setDoSomethingValue(someValue);
}, [editorState]);
旁注
更广泛地说,memo
是 HOC 并且使组件成为纯组件。 useMemo
是缓存函数输出的东西。而 useCallback
缓存函数的实例。
希望对您有所帮助。