簡體   English   中英

反應 useCallback 與參數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM