请考虑以下示例:
// Form.tsx
import React from "react";
interface FormProps {
name: string;
onClick: (n: string) => void;
}
export function Form(props: FormProps) {
console.log("Form rendered");
return (
<input type="button" onClick={() => props.onClick(props.name)} value={`Hello ${props.name}`}/>
);
}
// App.tsx
import React, { useState, useCallback } from 'react';
import './App.css';
import { Form } from './Form';
interface AppState {
val: number;
}
interface AppProps {
}
export function App(props: AppProps) {
const [val, setVal] = useState(1);
const onClick = useCallback(
(n: string) => {
console.log(val);
setVal(val + 1);
},
[val],
);
return (
<div>
<p>Value: {val}</p>
<Form name="foo" onClick={onClick}/>
</div>
);
}
我将一个道具和一个回调传递给Form
组件。调用回调时,它将更新val
状态。该状态未在<Form>
元素中使用,但是React仍会重新渲染它(Form rendered
被打印到控制台)。
这似乎是不必要的。 useCallback()
documentation说:
useCallback将返回回显的回调版本,仅在其中一个依赖项已更改时才更改。当将回调传递给依赖引用相等的优化子组件以防止不必要的渲染时,这很有用
这是非常模棱两可的,但是似乎建议可以将组件配置为仅在其任何prop值更改时进行更新,并且不使用useCallback()
意味着每次{{1 }}被调用,因此App()
将始终更新。
由于它说“优化”的子组件,大概不是默认行为吗?但为什么?如果道具没有变化,为什么还要更新?通过Form
“优化”组件的全部要点是否比“改变道具”更为轻松?
答案 0 :(得分:0)
当您将状态(val
)作为对useCallback()
的依赖项传递时,val
更改时会生成一个新函数。这将导致子组件重新呈现。
要跳过将val
作为依赖项的需要,同时又想更新它时仍具有先前状态的值,请使用updater function:
如果新状态是使用先前状态计算的,则可以传递一个 函数为setState。该函数将接收先前的值, 并返回更新的值。
示例:
const onClick = useCallback(
(n: string) => {
setVal(v => v + 1);
},
[],
);