[英]React useCallback with Parameter
使用 React 的useCallback
鈎子本質上只是一個專門用於函數的useMemo
的包裝器,以避免在組件的 props 中不斷創建新的 function 實例。 我的問題來自何時需要將爭論傳遞給從記憶創建的回調。
例如,像這樣創建的回調......
const Button: React.FunctionComponent = props => {
const onClick = React.useCallback(() => alert('Clicked!'), [])
return <button onClick={onClick}>{props.children}</button>
}
是記憶回調的一個簡單示例,不需要向其中傳遞任何外部值即可完成其工作。 但是,如果我想為React.Dipatch<React.SetStateAction>
function 類型創建一個通用的記憶回調,那么它需要 arguments...例如:
const Button: React.FunctionComponent = props => {
const [loading, setLoading] = React.useState(false)
const genericSetLoadingCb = React.useCallback((x: boolean) => () => setLoading(x), [])
return <button onClick={genericSetLoadingCb(!loading)}>{props.children}</button>
}
在我看來,這似乎與執行以下操作完全相同......
const Button: React.FunctionComponent = props => {
const [loading, setLoading] = React.useState(false)
return <button onClick={() => setLoading(!loading)}>{props.children}</button>
}
這將破壞記憶 function 的目的,因為它仍然會在每個渲染上創建一個新的 function,因為genericSetLoadingCb(false)
也會在每個渲染上返回一個新的 function。
這種理解是否正確,或者 arguments 描述的模式是否仍然保持記憶化的好處?
為了下面的示例,我將使用genericCb
function 而不是您所擁有的genericSetLoadingCb
。
const genericCb = React.useCallback((param) => () => someFunction(param), [])
我們上面所做的是確保 function genericCb
在重新渲染中保持不變。 但是,每次您創建一個新的 function 時,如下所示:
genericCb("someParam")
返回的 function在每次渲染時都會有所不同。 為了確保返回的 function 被記憶,你需要這樣的東西:
let memoizedCb = React.useCallback(
memoize((param) => () => someFunction(param)),
[]
);
我使用快速記憶,例如
import memoize from "fast-memoize";
現在,如果您使用memoizedCb("someParam")
生成 function,它將在每次渲染時返回相同的 function,前提是"someParam"
也保持不變。
注意:正如評論中指出的那樣,這種方法似乎會產生警告(雖然它沒有出現在我的項目中):
React Hook useCallback 收到一個 function ,其依賴關系未知。 改為傳遞內聯 function
似乎警告在那里,因為我們將memoize
傳遞給useCallback
,它再也看不到依賴關系,也無法警告您可能的過時閉包。 在這種情況下,恕我直言,用戶可以檢查是否有任何陳舊的閉包。
簡單地使用 memoize 而不使用useCallback
是行不通的,因為在下一次渲染時,它會像這樣從新調用 memoize:
let memoized = memoize(fn)
memoized('foo', 3, 'bar')
memoized('foo', 3, 'bar') // cache hit
memoized = memoize(fn); // without useCallback this would happen on next render
// Now the previous cache is lost
似乎執行以下操作是解決您的問題的一種優雅而簡單的方法。 如果 Button 只是重新渲染,它不會創建新的 cb function。
const Button = props => {
const [loading, setLoading] = React.useState(false)
const cb = React.useCallback(() => { setLoading(!loading) }, [loading]);
return <button onClick={cb}>{props.children}</button>
}
我建議為每個可能的參數值創建一個 map 的記憶回調:
const genericSetLoadingCb = React.useMemo(() =>
{
[true]: () => setLoading(true),
[false]: () => setLoading(false),
},
[]
);
因此,每個值的記憶版本都是相同的:
return <button onClick={genericSetLoadingCb[!loading]}>{props.children}</button>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.