欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React?useCallback使用方法詳解

 更新時(shí)間:2025年01月21日 08:21:42   作者:前端涂涂  
useCallback?是?React?的一個(gè)?Hook,用于記憶函數(shù)定義,避免在每次渲染時(shí)創(chuàng)建新的函數(shù)實(shí)例,本文主要來(lái)介紹一下它的具體用法,需要的可以參考一下

1. useCallback 基礎(chǔ)概念

useCallback 是 React 的一個(gè) Hook,用于記憶函數(shù)定義,避免在每次渲染時(shí)創(chuàng)建新的函數(shù)實(shí)例。它在需要將回調(diào)函數(shù)傳遞給經(jīng)過(guò)優(yōu)化的子組件時(shí)特別有用。 當(dāng)state變化的時(shí)候引起組件重新渲染執(zhí)行會(huì)導(dǎo)致某個(gè)方法被反復(fù)創(chuàng)建增加內(nèi)存負(fù)擔(dān),這個(gè)時(shí)候可以使用useCallback將該函數(shù)進(jìn)行緩存,只創(chuàng)建一次

1.1 基本語(yǔ)法

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b], // 依賴項(xiàng)數(shù)組
);

同樣的當(dāng)依賴項(xiàng)省略時(shí)組件重新渲染都會(huì)執(zhí)行,當(dāng)依賴項(xiàng)為空數(shù)組的時(shí)候只有組件初始化的時(shí)候會(huì)執(zhí)行一次,數(shù)組里有依賴項(xiàng)的時(shí)候依賴項(xiàng)發(fā)生變化的時(shí)候都會(huì)緩存一次

1.2 與普通函數(shù)的區(qū)別

function ParentComponent() {
  const [count, setCount] = useState(0);

  // ? 每次渲染都會(huì)創(chuàng)建新的函數(shù)實(shí)例
  const handleClick = () => {
    console.log('Clicked');
  };

  // ? 函數(shù)實(shí)例會(huì)被記憶,只在依賴項(xiàng)變化時(shí)更新
  const handleClickMemoized = useCallback(() => {
    console.log('Clicked');
  }, []); // 空依賴數(shù)組,函數(shù)永遠(yuǎn)不會(huì)改變

  return <ChildComponent onClick={handleClickMemoized} />;
}

2. useCallback 配合 React.memo 使用

2.1 基本示例

// 子組件使用 React.memo 優(yōu)化
const ChildComponent = React.memo(function ChildComponent({ onClick }) {
  console.log("ChildComponent rendered");
  return <button onClick={onClick}>Click me</button>;
});

// 父組件使用 useCallback
function ParentComponent() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState("");

  // 使用 useCallback 記憶回調(diào)函數(shù)
  const handleClick = useCallback(() => {
    setCount(c => c + 1);
  }, []); // 空依賴數(shù)組,因?yàn)椴灰蕾嚾魏沃?

  return (
    <div>
      <input value={text} onChange={e => setText(e.target.value)} />
      <p>Count: {count}</p>
      <ChildComponent onClick={handleClick} />
    </div>
  );
}

2.2 帶有依賴項(xiàng)的示例

function SearchComponent({ onSearch }) {
  const [searchTerm, setSearchTerm] = useState("");
  const [searchHistory, setSearchHistory] = useState([]);

  // 使用 useCallback 記憶搜索函數(shù)
  const handleSearch = useCallback(() => {
    if (searchTerm.trim()) {
      onSearch(searchTerm);
      setSearchHistory(prev => [...prev, searchTerm]);
    }
  }, [searchTerm, onSearch]); // 依賴 searchTerm 和 onSearch

  return (
    <div>
      <input
        value={searchTerm}
        onChange={e => setSearchTerm(e.target.value)}
      />
      <SearchButton onClick={handleSearch} />
      <SearchHistory items={searchHistory} />
    </div>
  );
}

// 優(yōu)化的子組件
const SearchButton = React.memo(function SearchButton({ onClick }) {
  console.log("SearchButton rendered");
  return <button onClick={onClick}>搜索</button>;
});

const SearchHistory = React.memo(function SearchHistory({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
});

3. 實(shí)際應(yīng)用場(chǎng)景

3.1 表單處理

function ComplexForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: ''
  });

  // 記憶表單字段更新函數(shù)
  const handleFieldChange = useCallback((fieldName) => (event) => {
    setFormData(prev => ({
      ...prev,
      [fieldName]: event.target.value
    }));
  }, []); // 不需要依賴項(xiàng),因?yàn)槭褂昧撕瘮?shù)式更新

  return (
    <form>
      <FormField
        label="Name"
        value={formData.name}
        onChange={handleFieldChange('name')}
      />
      <FormField
        label="Email"
        value={formData.email}
        onChange={handleFieldChange('email')}
      />
      <FormField
        label="Message"
        value={formData.message}
        onChange={handleFieldChange('message')}
      />
    </form>
  );
}

const FormField = React.memo(function FormField({ label, value, onChange }) {
  console.log(`${label} field rendered`);
  return (
    <div>
      <label>{label}</label>
      <input value={value} onChange={onChange} />
    </div>
  );
});

3.2 列表渲染優(yōu)化

function TodoList() {
  const [todos, setTodos] = useState([]);

  // 記憶添加任務(wù)函數(shù)
  const handleAdd = useCallback((text) => {
    setTodos(prev => [...prev, { id: Date.now(), text, completed: false }]);
  }, []);

  // 記憶切換完成狀態(tài)函數(shù)
  const handleToggle = useCallback((id) => {
    setTodos(prev =>
      prev.map(todo =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  }, []);

  // 記憶刪除函數(shù)
  const handleDelete = useCallback((id) => {
    setTodos(prev => prev.filter(todo => todo.id !== id));
  }, []);

  return (
    <div>
      <AddTodo onAdd={handleAdd} />
      {todos.map(todo => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onToggle={handleToggle}
          onDelete={handleDelete}
        />
      ))}
    </div>
  );
}

const TodoItem = React.memo(function TodoItem({ todo, onToggle, onDelete }) {
  return (
    <div>
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={() => onToggle(todo.id)}
      />
      <span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
        {todo.text}
      </span>
      <button onClick={() => onDelete(todo.id)}>刪除</button>
    </div>
  );
});

4. 性能優(yōu)化最佳實(shí)踐

4.1 合理使用依賴項(xiàng)

function UserProfile({ userId, onUpdate }) {
  // ? 只在 userId 或 onUpdate 變化時(shí)更新
  const handleUpdate = useCallback(() => {
    onUpdate(userId);
  }, [userId, onUpdate]);

  // ? 不必要的依賴項(xiàng)
  const handleClick = useCallback(() => {
    console.log('Clicked');
  }, [userId]); // userId 不需要作為依賴項(xiàng)
}

4.2 避免過(guò)度優(yōu)化

// ? 簡(jiǎn)單組件不需要使用 useCallback
function SimpleButton({ onClick }) {
  return <button onClick={onClick}>Click me</button>;
}

// ? 復(fù)雜組件或頻繁重渲染的組件使用 useCallback
const ComplexComponent = React.memo(function ComplexComponent({ onAction }) {
  // 復(fù)雜的渲染邏輯
  return (
    // ...
  );
});

5. useCallback 與其他 Hooks 配合

5.1 配合 useEffect 使用

function DataFetcher({ query }) {
  const [data, setData] = useState(null);

  // 記憶獲取數(shù)據(jù)的函數(shù)
  const fetchData = useCallback(async () => {
    const response = await fetch(`/api/search?q=${query}`);
    const result = await response.json();
    setData(result);
  }, [query]);

  // 在 effect 中使用記憶的函數(shù)
  useEffect(() => {
    fetchData();
  }, [fetchData]); // fetchData 作為依賴項(xiàng)

  return <div>{/* 渲染數(shù)據(jù) */}</div>;
}

5.2 配合 useMemo 使用

function DataProcessor({ data, onProcess }) {
  // 記憶處理函數(shù)
  const processData = useCallback((item) => {
    // 復(fù)雜的數(shù)據(jù)處理邏輯
    return someExpensiveOperation(item);
  }, []);

  // 使用記憶的函數(shù)處理數(shù)據(jù)
  const processedData = useMemo(() => {
    return data.map(processData);
  }, [data, processData]);

  return (
    <div>
      {processedData.map(item => (
        <ProcessedItem
          key={item.id}
          item={item}
          onProcess={onProcess}
        />
      ))}
    </div>
  );
}

6. 注意事項(xiàng)

避免過(guò)度使用

  • 只在性能確實(shí)受影響時(shí)使用
  • 簡(jiǎn)單組件和回調(diào)不需要使用 useCallback

正確設(shè)置依賴項(xiàng)

  • 包含所有回調(diào)中使用的變量
  • 避免不必要的依賴項(xiàng)

配合 React.memo 使用

  • 單獨(dú)使用 useCallback 可能無(wú)法帶來(lái)性能提升
  • 需要配合 React.memo 等優(yōu)化手段

考慮使用場(chǎng)景

  • 頻繁重渲染的組件
  • 復(fù)雜的計(jì)算或操作
  • 傳遞給多個(gè)子組件的回調(diào)

通過(guò)合理使用 useCallback 和 React.memo,我們可以有效優(yōu)化 React 應(yīng)用的性能。但要記住,過(guò)度優(yōu)化可能會(huì)適得其反,應(yīng)該在實(shí)際需要時(shí)才進(jìn)行優(yōu)化。

到此這篇關(guān)于React useCallback使用方法詳解的文章就介紹到這了,更多相關(guān)React useCallback內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • react+antd實(shí)現(xiàn)動(dòng)態(tài)編輯表格數(shù)據(jù)

    react+antd實(shí)現(xiàn)動(dòng)態(tài)編輯表格數(shù)據(jù)

    這篇文章主要為大家詳細(xì)介紹了react+antd實(shí)現(xiàn)動(dòng)態(tài)編輯表格數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • React路由的history對(duì)象的插件history的使用解讀

    React路由的history對(duì)象的插件history的使用解讀

    這篇文章主要介紹了React路由的history對(duì)象的插件history的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • React antd tabs切換造成子組件重復(fù)刷新

    React antd tabs切換造成子組件重復(fù)刷新

    這篇文章主要介紹了React antd tabs切換造成子組件重復(fù)刷新,需要的朋友可以參考下
    2021-04-04
  • React 路由懶加載的幾種實(shí)現(xiàn)方案

    React 路由懶加載的幾種實(shí)現(xiàn)方案

    這篇文章主要介紹了React 路由懶加載的幾種實(shí)現(xiàn)方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-10-10
  • React項(xiàng)目經(jīng)驗(yàn)總結(jié)及遇到的坑

    React項(xiàng)目經(jīng)驗(yàn)總結(jié)及遇到的坑

    這篇文章主要介紹了React項(xiàng)目經(jīng)驗(yàn)總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • 在react中對(duì)less實(shí)現(xiàn)scoped配置方式

    在react中對(duì)less實(shí)現(xiàn)scoped配置方式

    這篇文章主要介紹了在react中對(duì)less實(shí)現(xiàn)scoped配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • React實(shí)現(xiàn)動(dòng)效彈窗組件

    React實(shí)現(xiàn)動(dòng)效彈窗組件

    最近在使用react開(kāi)發(fā)項(xiàng)目,遇到這樣一個(gè)需求實(shí)現(xiàn)一個(gè)帶有動(dòng)效的 React 彈窗組件,如果不考慮動(dòng)效,很容易實(shí)現(xiàn),接下來(lái)小編通過(guò)本文給大家介紹React實(shí)現(xiàn)動(dòng)效彈窗組件的實(shí)現(xiàn)代碼,一起看看吧
    2021-06-06
  • React 中引入 CSS 高階用法的方案詳解

    React 中引入 CSS 高階用法的方案詳解

    這篇文章主要介紹了React中引入CSS高階用法的方案詳解,至于使用react用哪種方案引入css,并沒(méi)有一個(gè)絕對(duì)的答案,可以根據(jù)各自情況選擇合適的方案,需要的朋友可以參考下
    2024-02-02
  • React?18?如何更新?state?中的對(duì)象

    React?18?如何更新?state?中的對(duì)象

    state 中可以保存任意類型的JavaScript值,包括對(duì)象,但是,不應(yīng)該直接修改存放在 React state 中的對(duì)象,這篇文章主要介紹了React?18更新state中的對(duì)象,需要的朋友可以參考下
    2023-08-08
  • React-Native之TextInput組件的設(shè)置以及如何獲取輸入框的內(nèi)容

    React-Native之TextInput組件的設(shè)置以及如何獲取輸入框的內(nèi)容

    這篇文章主要介紹了React-Native之TextInput組件的設(shè)置以及如何獲取輸入框的內(nèi)容問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05

最新評(píng)論