常用react hook分析

简介: useMemo、useCallBack、useState、useRef、React.memo()的使用

1、useMemo、useCallBack
useMemo:

  • const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); 返回一個memoized 值。
  • 它能夠避免組件每次重新渲染時重複進行複雜的計算,參數為一個函數和可選的依賴項數組。當不傳依賴項時,隨著組件重新渲染重新計算;當傳入空數組依賴項時,只會返回首次渲染的計算結果;當有傳入的依賴項發生變化時,會重新計算結果並返回。為了達到優化效果,計算函数中引用的值都应该出现在依赖项数组裡。
  • 雖然传入 useMemo 的函数会在渲染期间执行。但最好不要在這個函數內部執行與渲染無關的操作,如副作用(請求接口等)這類的操作屬於 useEffect 的適用範疇,而不是 useMemo。

useCallBack:

  • const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);返回一个 memoized 回调函数。依賴項用法與useMemo類似。但需要注意的是,當依賴項數組為空時,傳入useCallback的函數的內部通过閉包取得組件內的變量值始終不變。
  • useCallBack更常用於減少子組件的重新渲染,需要子組件配合React.memo或者shouldComponentUpdate使用。但如果依賴項變化頻率很高,子組件依然多次重複渲染,我會考慮用ahook的usePersistFn替換useCallBack使用。

對比:兩者都是優化渲染性能的手段方法,useMemo返回的是值而useCallBack返回的是函數,且useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。

2、useState、useRef

  • useState的值在每個render中都是獨立存在的,而useRef.current更像是相對於render函數中的一個全局變量,每次render都會保持最新的狀態。
  • useState值更新會觸發組件重新渲染,而useRef.current不會觸發重新渲染。
  • useRef.current是可變的,能保存任何值,不僅僅用於Dom引用,可當類實例去使用。

3、React.memo()
這是一個高階方法,React.memo()的返回值是一個新的函數組件。在組件中,props或state發生變化,組件就會重新渲染,如果父組件需要經常更新數據,但其實傳給子組件的props並沒有發生變化,但是子組件卻依然要更新,這樣會增加消耗。所以react.memo就是用來給子組件裹上一層,props不發生變化時(淺對比),組件不需要重新渲染。react.memo()只能用於函數組件,類似於類組件中的pureComponent、shouldComponentUpdate的功能。它可接受2个参数,第一个参数为纯函数组件,第二个参数用于对比props控制是否刷新的,与shouldComponentUpdate功能类似。
相關代碼:
图8.png

Demo(涉及useState、useRef、useMemo、useCallBack,react.memo的使用)
最初的版本:
父组件: 記錄name和age兩個變量, 可點擊按鈕增加年齡。
子组件: 記錄組件本身渲染的次數,顯示父組件的信息。
图9.png
图10.png

图1(子组件随着父组件渲染而重新渲染).png

a.Parent傳給Child的props並沒有發生變化,但是只要age發生變化,父組件重新渲染,子組件也會渲染,子組件用react.memo包裹就能解決這個問題。

const Child = React.memo(({ name }) => {
 ...略
});
AI 代码解读

图2(优化后的子组件减少渲染次数).png

b.當我在父組件中把較為複雜的數據類型傳給子組件(如下),父組件修改age後,子組件也跟著重新渲染了(如图1),是react.memo失效了嗎?其實是父组件渲染時,const info = { name, age } 一行会重新生成一个新對象,導致傳遞给子组件的 info 屬性值變化,就導致子組件重新渲染。
圖11.png

解決方案如下,只有当name发生变化时,才会重新计算info的结果,这样当父组件修改age时,子组件就不会再渲染了(如图2)。
圖3.png

c.当我给子组件一个方法能修改父组件的名字时(如下)
圖12.png
图13.png
圖4.png

修改父组件age时会引起子组件重新渲染,是因为父组件每次渲染都会重新构建一个changeName方法(返回不同的引用地址),也是传给子组件的props发生了变化,所以重新渲染,但其实这是没必要的,修改方案如下:
圖5.png
结果:
圖6.png

d.如果changeName方法修改的新名字依赖age(如下),useCallBack的依賴項依然為空數組的話,這樣不管父組件的age增大到多少,子組件點擊changeName一直都是 newName 0。但是把useCallBack的依賴設置為[age]以後,這樣父組件修改age以後會引起changeName引用地址變化從而導致子組件重新渲染,這時候可以用usePersistFn替換useCallBack使用,用来解决useCallBack的依賴項變化頻率過高导致的子组件重複渲染問題。
圖7.png

4、自定義hook
組件由ui和邏輯組成,自定義hook可以將邏輯提取到可重用的函數中。要注意的是,與 React 組件不同的是,自定義 Hook 不需要具有特殊的標識。我們可以決定它的參數是什麽,以及它應該返回什麽。換句話說,它就像一個正常的函數,但是它的名字應該始終以 use 開頭。我之前很少寫自定義hook,但是最近有經常用到一個項目別人寫的hook代碼,哎真香,看來平時自己還是得多總結多提取,才會有進步啊。最近經常用到的自定義hook:

import { useState, useEffect, useCallback } from 'react';
import { message } from 'antd';

export default function useTablePage(service, options = {}) {
  const { defaultPageNum = 1, defaultPageSize = 10, defaultQueryParam = {} } = options;
  const [loading, setLoading] = useState(false);
  const [params, setParams] = useState({
    pageNum: defaultPageNum,
    pageSize: defaultPageSize,
    ...defaultQueryParam,
  });
  const [listData, setListData] = useState([]);
  const [total, setTotal] = useState(0);

  const _getTableData = useCallback(() => {
    setLoading(true);
    service(params).then(({ success, message: errMsg, data, code }) => {
      setLoading(false);
      if (!success && code !== '61200130') {
        message.error(errMsg);
        return;
      }
      setListData(data?.list);
      setTotal(data?.totalCount);
    });
  }, [service, params]);

  const loadTableData = useCallback((curParams = {}) => {
    setParams((prev = {}) => ({
      ...prev,
      ...curParams,
    }));
  }, []);

  const handleFilter = useCallback(
    (pagination) => {
      const { current: pageNum, pageSize } = pagination;
      loadTableData({
        pageNum,
        pageSize,
        // timeSort: sorter.order === 'ascend' ? 0 : 1
      });
    },
    [loadTableData]
  );

  useEffect(() => {
    _getTableData();
  }, [_getTableData]);

  return {
    loadTableData,
    tableProps: {
      dataSource: listData,
      onChange: handleFilter,
      loading,
      pagination: {
        current: params.pageNum,
        pageSize: params.pageSize,
        showSizeChanger: true,
        showQuickJumper: true,
        total,
      },
    },
  };
}
AI 代码解读

使用:
圖14.png

目录
打赏
0
0
0
0
1
分享
相关文章
Flutter 与 React Native - 详细深入对比分析(2024 年)
Flutter和React Native是两大跨平台框架,各有优缺点。Flutter性能优越,UI灵活,使用Dart;React Native生态广泛,适合JavaScript开发。
1997 5
Flutter 与 React Native - 详细深入对比分析(2024 年)
前端优化之超大数组更新:深入分析Vue/React/Svelte的更新渲染策略
本文对比了 Vue、React 和 Svelte 在数组渲染方面的实现方式和优缺点,探讨了它们与直接操作 DOM 的差异及 Web Components 的实现方式。Vue 通过响应式系统自动管理数据变化,React 利用虚拟 DOM 和 `diffing` 算法优化更新,Svelte 通过编译时优化提升性能。文章还介绍了数组更新的优化策略,如使用 `key`、分片渲染、虚拟滚动等,帮助开发者在处理大型数组时提升性能。总结指出,选择合适的框架应根据项目复杂度和性能需求来决定。
187 2
探索React状态管理:Redux的严格与功能、MobX的简洁与直观、Context API的原生与易用——详细对比及应用案例分析
【8月更文挑战第31天】在React开发中,状态管理对于构建大型应用至关重要。本文将探讨三种主流状态管理方案:Redux、MobX和Context API。Redux采用单一存储模型,提供预测性状态更新;MobX利用装饰器语法,使状态修改更直观;Context API则允许跨组件状态共享,无需第三方库。每种方案各具特色,适用于不同场景,选择合适的工具能让React应用更加高效有序。
142 0
【性能奇迹】Wicket应用的极速重生:揭秘那些让开发者心跳加速的调优秘技!
【8月更文挑战第31天】在软件开发中,性能优化是确保应用快速响应和高效运行的关键。本书《性能调优:Apache Wicket应用的速度提升秘籍》详细介绍了如何优化Apache Wicket应用,包括代码优化、资源管理、数据库查询优化、缓存策略及服务器配置等方面。通过减少不必要的组件渲染、优化SQL查询、使用缓存和调整服务器设置等方法,本书帮助开发者显著提升Wicket应用的性能,确保其在高并发和数据密集型场景下的稳定性和响应速度。
65 0
探索现代Web开发中的框架选择:Blazor、Angular和React的全面比较与分析
【8月更文挑战第31天】随着Web开发技术的发展,选择合适的框架对项目成功至关重要。本文对比了三大前端框架:Blazor、Angular和React。Blazor是微软推出的.NET Web客户端开发框架,支持C#编写前端代码;Angular由Google支持,基于TypeScript,适用于大型应用;React是由Facebook维护的高效JavaScript库。
213 0
移动应用开发中的跨平台策略:React Native与Flutter的比较分析
【8月更文挑战第31天】 在快速变化的移动应用市场,开发者面临着如何在众多平台间高效部署应用的挑战。本文将深入探讨两种主流的跨平台移动应用开发框架——React Native和Flutter,通过对比它们的核心特性、性能表现以及社区生态,为开发者提供选择框架时的参考依据。我们将借助代码示例,展现两者在实际开发中的应用差异,并分析各自的优势和潜在局限,以期帮助开发者根据项目需求做出明智的技术选型。
|
8月前
|
React 中的 Hook 概念
【8月更文挑战第31天】
94 0
React useImperativeHandle Hook
【7月更文挑战第1天】React useImperativeHandle Hook
48 3
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
169 1
深度分析:React Native、Flutter、UniApp、Taro、Vue的差异
深度分析:React Native、Flutter、UniApp、Taro、Vue的差异
651 6
下一篇
oss创建bucket