簡體   English   中英

什么時候在 React 中使用 useCallback?

[英]When to use useCallback in React?

我已經閱讀了幾篇關於useCallbackuseMemo關於何時使用和何時不使用的文章,但我大多看到的是非常contrived代碼。 我正在查看我公司的代碼,我注意到有人這樣做了:

const takePhoto = useCallback(() => {
    launchCamera({ mediaType: "photo", cameraType: "front" }, onPickImage);
  }, []);

  const pickPhotoFromLibrary = async () => {
    launchImageLibrary({ mediaType: "photo" }, onPickImage);
  }

  const onUploadPress = useCallback(() => {
    Alert.alert(
      "Upload Photo",
      "From where would you like to take your photo?",
      [
        { text: "Camera", onPress: () => takePhoto() },
        { text: "Library", onPress: () => pickPhotoFromLibrary() },
      ]
    );
  }, [pickPhotoFromLibrary, takePhoto]);

這就是 onUploadPress 的調用方式:

    <TouchableOpacity
                    style={styles.retakeButton}
                    onPress={onUploadPress}
                  >

你認為這是正確的稱呼方式嗎? 根據我對這些文章的理解,這看起來是不正確的。 有人可以告訴我何時使用useCallback並且還可以用更人性化的方式解釋 useCallback 嗎?

我閱讀的文章: https://kentcdodds.com/blog/usememo-and-usecallback

一、概述

useCallback返回一個正常的 JavaScript function,關於如何使用它。 它與它作為第一個參數獲得的關於它做什么的參數相同。 雖然返回的 function 被記住了。 這意味着當您的組件重新渲染時,React 不會重新創建 function(這是組件內正常 function 的行為)。

如果數組中的一個變量( useCallback的第二個參數)發生變化,React 將重新創建該 function 的新版本。 例如,如果你在 useEffect 的依賴項數組中有useEffect是值得的。 如果您將它傳遞給使用React.memo的組件,這也是值得的。

useEffect的回調在第一次渲染時被調用,並且每次依賴數組中的一個變量發生變化時。 而且由於通常每次重新渲染組件時都會創建 function 的新版本,因此可能會無限調用回調。 這就是為什么使用useCallback來記憶 function。

僅當其stateprops發生更改時,memoized 組件才會重新渲染,而不是因為其父級重新渲染。 並且因為通常在父組件重新渲染時會創建一個通過 function 的新版本,所以子組件會獲得該 function 的新引用,因此它會重新渲染。 這就是為什么使用useCallback來記憶傳遞的function。

2.重要提示

記憶不是免費的。 糟糕的記憶比沒有記憶更糟糕。 這是我所見過的最完整和最短的資源,用於深入理解 React 渲染過程,以了解何時記憶以及何時不記憶: React Render 教程

3. 你的用例

在您的情況下,將useCallback用於onUploadPress會浪費性能,因為pickPhotoFromLibrary ,未記憶的 function 位於依賴項數組中。 如果TouchableOpacity沒有用React.memo ,那也會浪費性能,我不確定是不是這樣。

簡單來說, useCallback用於將 function 引用保存在組件渲染之外的某個位置,因此我們可以再次使用相同的引用。 每當依賴項數組中的變量之一發生更改時,該引用就會更改。 如您所知, React嘗試通過觀察一些變量的值變化來最小化重新渲染過程,然后它決定重新渲染,而不依賴於這些變量的舊值和新值。 因此, useCallback的基本用法是平等地保存舊值和新值。

我將通過在必須使用useCalback的情況下給出一些示例來嘗試更多地演示它。

  • 示例 1:當 function 是useEffect的依賴項數組之一時。
function Component(){
  const [state, setState] = useState()
  
  // Should use `useCallback`
  function handleChange(input){
    setState(...)
  }

  useEffect(()=>{
    handleChange(...)
  },[handleChange])

  return ...
}
  • 示例 2:當 function 被傳遞給其中一個子組件時。 特別是在他們的useEffect鈎子上調用它時,它會導致無限循環。
function Parent(){
  const [state, setState] = useState()
  
  function handleChange(input){
    setState(...)
  }

  return <Child onChange={handleChange} />
}

function Child({onChange}){
  const [state, setState] = useState()
  
  useEffect(()=>{
    onChange(...)
  },[onChange])

  return "Child"
}
  • 示例 3:當您使用包含 state 並僅返回 state 設置器函數的React Context時,您需要該context的使用者不要在每次 Z9ED39E2EA931586B6E3A985A6942EF5 更新時重新渲染它,因為它可能會損害性能。
const Context = React.createContext();

function ContextProvider({children}){
  const [state, setState] = useState([]);
  
  // Should use `useCallback`
  const addToState = (input) => {
    setState(prev => [...prev, input]);
  }

  // Should use `useCallback`
  const removeFromState = (input) => {
    setState(prev => prev.filter(elem => elem.id !== input.id));
  }

  // Should use `useCallback` with empty []
  const getState = () => {
    return state;
  }

  const contextValue= React.useMemo(
    () => ({ addToState , removeFromState , getState}),
    [addToState , removeFromState , getState]
  );

  // if we used `useCallback`, our contextValue will never change and all the subscribers will not re-render
  <Context.Provider value={contextValue}>
    {children}
  </Context.Provider>
}

示例 4:如果訂閱了觀察者、定時器、文檔事件,並且在組件卸載時或其他任何原因需要取消訂閱。 所以我們需要訪問相同的引用來取消訂閱。

function Component(){

  // should use `useCallback`
  const handler = () => {...}
  
  useEffect(() => {
    element.addEventListener(eventType, handler)
    return () => element.removeEventListener(eventType, handler)
  }, [eventType, element])


  return ...
}

就是這樣,您也可以在多種情況下使用它,但我希望這些示例展示了useCallback背后的主要思想。 並且永遠記住,如果重新渲染的成本可以忽略不計,你就不需要使用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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