中文

探索 React useEvent hook,這是一個/这是一个功能強大/大的工具,可在動態/动态 React 應用/应用中創建/创建穩定的/稳定的事件處理器/处理器引用,從而/从而提高性能並/并防止不必要的重新渲染。

React useEvent:實現/实现穩定的/稳定的事件處理器/处理器引用

React 開發者/开发者在處理/处理事件處理器/处理器時/时,尤其是在涉及動態/动态組件/组件和閉包/闭包的場景/场景中,經常/经常會/会遇到挑戰/挑战。useEvent hook 是 React 生態系/生态系统中一個/一个較/较新的成員/成员,它為/为這些/这些問題/问题提供了一個/一个優雅的/优雅的解決/解决方案,讓/让開發者/开发者能夠/能够創建/创建不會/会觸發/触发不必要重新渲染的穩定/稳定的事件處理器/处理器引用。

理解問題/问题:事件處理器/处理器的不穩定性/不稳定性

在 React 中,當/当組件/组件的 props 或 state 發生/生變化/变化時/时,它會/会重新渲染。當/当一個/一个事件處理器/处理器函數/函数作為/为 prop 傳遞/传递時/时,通常在父組件/组件的每次渲染上都會/会創建/创建一个新的函數/函数實例/实例。這個/这个新的函數/函数實例/实例,即使其邏輯/逻辑相同,也會/会被 React 視為/视为不同,從而/从而導致/导致接收它的子組件/组件重新渲染。

請看/请看這個/这个簡單的/简单的例子:


import React, { useState } from 'react';

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

  const handleClick = () => {
    console.log('Clicked from Parent:', count);
    setCount(count + 1);
  };

  return (
    

Count: {count}

); } function ChildComponent({ onClick }) { console.log('ChildComponent rendered'); return ; } export default ParentComponent;

在這個/这个例子中,handleClickParentComponent 的每次渲染時/时都會/会被重新創建/创建。即使 ChildComponent 可能已經/已经過/过優化/优化(例如,使用 React.memo),它仍然會/会因為/为 onClick prop 的改變/改变而重新渲染。這/这可能導致/导致性能問題/问题,尤其是在複雜的/复杂的應用/应用中。

useEvent 介紹/介绍:解決/解决之道

useEvent hook 通過/过提供一個/一个穩定/稳定的事件處理器/处理器函數/函数引用來/来解決/解决這個/这个問題/问题。它有效地將/将事件處理器/处理器與/与其父組件/组件的重新渲染週期/周期解耦。

雖然/虽然 useEvent 並/并非內建/内置的 React hook(截至 React 18),但它可以很容易地實現/实现為/为一個/一个自訂/自定义 hook,或者在某些框架和函式庫/函数库中,它作為/为其實用/实用工具集的一部分提供。以下是一個/一个常見/常见的實現/实现方式:


import { useCallback, useRef, useLayoutEffect } from 'react';

function useEvent any>(fn: T): T {
  const ref = useRef(fn);

  // UseLayoutEffect 在此對於同步更新至關重要/UseLayoutEffect 在此对于同步更新至关重要
  useLayoutEffect(() => {
    ref.current = fn;
  });

  return useCallback(
    (...args: Parameters): ReturnType => {
      return ref.current(...args);
    },
    [] // 依賴項數組刻意留空,以確保穩定性/依赖项数组刻意留空,以确保稳定性
  ) as T;
}

export default useEvent;

說明/说明:

在實踐/实践中使用 useEvent

現在/现在,讓我們/们使用 useEvent 來/来重構/构之前的例子:


import React, { useState, useCallback, useRef, useLayoutEffect } from 'react';

function useEvent any>(fn: T): T {
  const ref = useRef(fn);

  // UseLayoutEffect 在此對於同步更新至關重要/UseLayoutEffect 在此对于同步更新至关重要
  useLayoutEffect(() => {
    ref.current = fn;
  });

  return useCallback(
    (...args: Parameters): ReturnType => {
      return ref.current(...args);
    },
    [] // 依賴項數組刻意留空,以確保穩定性/依赖项数组刻意留空,以确保稳定性
  ) as T;
}

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

  const handleClick = useEvent(() => {
    console.log('Clicked from Parent:', count);
    setCount(count + 1);
  });

  return (
    

Count: {count}

); } function ChildComponent({ onClick }) { console.log('ChildComponent rendered'); return ; } export default ParentComponent;

通過/过用 useEvent 包裝/装 handleClick,我們/们確保/确保了即使 count 狀態/状态改變/改变,ChildComponentParentComponent 的多次渲染中接收到的都是同一個/一个函數/函数引用。這/这防止了 ChildComponent 不必要的重新渲染。

使用 useEvent 的好處/好处

useEvent 的使用場景/场景

替代方案與/与考量/考量事項/事项

雖然/虽然 useEvent 是個/是个強大/强大的工具,但仍有一些替代方法和注意事項/注意事项需要牢記/牢记:

國際化/国际化與/与無障礙性/无障碍性考量/考量

為/为全球受眾/受众開發/开发 React 應用/应用時/时,考量/考量國際化/国际化 (i18n) 和無障礙性/无障碍性 (a11y) 至關重要/至关重要。useEvent 本身不會/会直接影響/影响 i18n 或 a11y,但它可以間接/间接改善處理/处理本地化內容/内容或無障礙性/无障碍性功能的組件/组件的性能。

例如,如果一個/一个組件/组件根據/根据當前/当前語言/语言顯示/显示本地化文本或使用 ARIA 屬性/属性,確保/确保該/该組件/组件內的/的事件處理器/处理器是穩定/稳定的,可以防止在語言/语言切換/切换時/时發生/生不必要的重新渲染。

範例/范例:useEvent 與/与本地化結合/结合


import React, { useState, useContext, createContext, useCallback, useRef, useLayoutEffect } from 'react';

function useEvent any>(fn: T): T {
  const ref = useRef(fn);

  // UseLayoutEffect 在此對於同步更新至關重要/UseLayoutEffect 在此对于同步更新至关重要
  useLayoutEffect(() => {
    ref.current = fn;
  });

  return useCallback(
    (...args: Parameters): ReturnType => {
      return ref.current(...args);
    },
    [] // 依賴項數組刻意留空,以確保穩定性/依赖项数组刻意留空,以确保稳定性
  ) as T;
}

const LanguageContext = createContext('en');

function LocalizedButton() {
  const language = useContext(LanguageContext);
  const [text, setText] = useState(getLocalizedText(language));

  const handleClick = useEvent(() => {
    console.log('Button clicked in', language);
    // 根據語言執行某些操作/根据语言执行某些操作
  });

  function getLocalizedText(lang) {
      switch (lang) {
        case 'en':
          return 'Click me';
        case 'fr':
          return 'Cliquez ici';
        case 'es':
          return 'Haz clic aquí';
        default:
          return 'Click me';
      }
    }

    //模擬語言切換/模拟语言切换
    React.useEffect(()=>{
        setTimeout(()=>{
            setText(getLocalizedText(language === 'en' ? 'fr' : 'en'))
        }, 2000)
    }, [language])

  return ;
}

function App() {
  const [language, setLanguage] = useState('en');

  const toggleLanguage = useCallback(() => {
    setLanguage(language === 'en' ? 'fr' : 'en');
  }, [language]);

  return (
    
      
); } export default App;

在這個/这个例子中,LocalizedButton 組件/组件根據/根据當前/当前語言/语言顯示/显示文本。通過/过為/为 handleClick 處理器/处理器使用 useEvent,我們/们確保/确保了當/当語言/语言改變/改变時/时,按鈕/按钮不會/会不必要地重新渲染,從而/从而改善了性能和用戶/用户體驗/体验。

結論/结论

useEvent hook 對/对於/于尋求/寻求優化/优化性能和簡化/简化組件/组件邏輯/逻辑的 React 開發者/开发者來/来说,是個/是个寶貴/宝贵的工具。通過/过提供穩定/稳定的事件處理器/处理器引用,它能防止不必要的重新渲染,提高程式碼/代码可讀性/可读性,並/并增強/增强 React 應用/应用的整體/体效率。雖然/虽然它不是 React 的內建/内置 hook,但其直接的實現/实现方式和顯著/显著的優點/优点使其值得被加入任何 React 開發者/开发者的工具箱中。

通過/过理解 useEvent 背後/后的原理及其使用場景/场景,開發者/开发者可以為/为全球受眾/受众建構/构建性能更高、更易於/易于維護/维护和更具擴展/扩展性的 React 應用/应用。請/请記住/记住,在應用/应用任何優化/优化技術/技术之前,務必/务必測量/测量性能並/并考量/考量您應用/应用的特定需求。