我在理解这些概念时遇到了麻烦,因为我从父函数中传递了一个子函数,所以子函数一直在重新渲染。这个父函数引用了一个编辑器的值,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组件是一个简单的按钮,调用父函数doSomething,仅此而已。
doSomething做它的事情,然后对状态进行改变,然后传递给AnotherChild。
我的问题是,每当编辑器状态被更新时(也就是每次在编辑器中输入时),我的Child组件就会重新渲染。这是不是没有必要?如果是这样,我如何避免这种情况?
如果我给我的Child组件传递一个字符串,并利用React.Memo,除非字符串改变,否则它不会重新渲染。
那么,我将一个函数传递给子组件,到底缺少了什么?我的Child应该每次都重新渲染吗?
React在引用变化检测上工作,以重新渲染组件。
Child.js
: 把它封装在 React.memo 遂成 纯组件.
const Child = ({doSomething}) => <button onClick={doSomething}>Child Button Name</button>;
export default React.memo(Child);
Parent.js -> doSomething
: 每次(重新)渲染时,也会重新创建回调。在每次(重)渲染时,回调也会被重新创建,利用 使用回调 这样你的函数就不会在每次渲染时重新创建。
const doSomething = React.useCallback(() => {
let userResponse = editorState.getCurrentContent().getPlainText("\u0001");
setDoSomethingValue(someValue);
}, [editorState]);
附注
在更广泛的线路上: memo
是HOC,使一个组件Pure Component。useMemo
是缓存函数输出的东西。而 useCallback
缓存该函数的实例。
希望能帮到你。
如果你不希望你的组件在每次你的父节点被重新渲染时都被重新渲染,你应该看一看 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.orgdocshooks-reference.html#usecallback。
看一看 PureComponent
, useMemo
或 shouldComponentUpdate
我还想补充一点,与其把函数传下来做顶层组件的渲染,不如把值传下来,然后在组件树的后面定义函数。
如果你想避免不必要的重渲染,你可以使用React.memo和挂钩useCallback。请看下面的内容 沙盒.button1总是被重新渲染,因为它采取了一个回调,而这个回调并没有使用回调(useCallback),button2只是第一次渲染,即使父节点的状态发生了变化(看看控制台来检查重新渲染的情况)。你必须在负责渲染按钮的Child组件中使用React.memo。
希望能帮到你。