useFocusEffect 和 useCallback 详解

useFocusEffect

useFocusEffect 是 React Navigation 提供的一个 Hook,专门用于处理页面获得焦点时的副作用。

基本用法:

import { useFocusEffect } from '@react-navigation/native';
import { useCallback } from 'react';

function MyScreen() {
  useFocusEffect(
    useCallback(() => {
      // 页面获得焦点时执行的代码
      console.log('页面获得焦点');
      
      // 返回清理函数(可选)
      return () => {
        console.log('页面失去焦点');
      };
    }, [])
  );
}

特点:

  • 每次页面获得焦点时都会执行
  • 支持清理函数,页面失去焦点时执行
  • 常用于数据刷新、订阅管理等场景

useCallback

useCallback 是 React 提供的性能优化 Hook,用于缓存函数引用。

基本语法:

const memoizedCallback = useCallback(
  () => {
    // 函数逻辑
  },
  [dependency1, dependency2] // 依赖数组
);

工作原理:

  • 只有当依赖数组中的值发生变化时,才会重新创建函数
  • 如果依赖数组为空 [],函数只会创建一次
  • 返回的是函数的缓存版本

使用场景:

  1. 防止子组件不必要的重渲染:

    function Parent() {
      const [count, setCount] = useState(0);
      
      // 没有 useCallback - 每次渲染都创建新函数
      const handleClick = () => {
     console.log('clicked');
      };
      
      // 使用 useCallback - 函数引用保持不变
      const memoizedHandleClick = useCallback(() => {
     console.log('clicked');
      }, []);
      
      return <Child onClick={memoizedHandleClick} />;
    }
  2. 与其他 Hook 配合使用:

    function MyComponent() {
      const [data, setData] = useState(null);
      
      const fetchData = useCallback(async () => {
     const result = await api.getData();
     setData(result);
      }, []); // 空依赖数组,函数只创建一次
      
      useEffect(() => {
     fetchData();
      }, [fetchData]); // fetchData 不会导致无限循环
    }

性能考虑

useCallback 的使用原则:

考虑使用:

  • 传递给子组件的函数
  • 作为其他 Hook 的依赖
  • 计算成本较高的函数

不考虑使用:

  • 简单的事件处理函数(如果没有传递给子组件)
  • 过度使用(useCallback 本身也有开销)

示例对比:

// 不需要 useCallback
function SimpleComponent() {
  const handleClick = () => {
    console.log('simple click');
  };
  
  return <button onClick={handleClick}>Click</button>;
}

// 需要 useCallback
function ComplexComponent({ children }) {
  const [count, setCount] = useState(0);
  
  const handleClick = useCallback(() => {
    // 复杂逻辑或传递给子组件
    setCount(prev => prev + 1);
  }, []);
  
  return (
    <div>
      {React.Children.map(children, child => 
        React.cloneElement(child, { onClick: handleClick })
      )}
    </div>
  );
}

总结

  • useFocusEffect:处理页面焦点变化的副作用,常用于数据刷新
  • useCallback:缓存函数引用,优化性能,防止不必要的重渲染
  • 结合使用:在导航场景中实现高效的数据刷新机制

这两个 Hook 在 React Native 应用中非常实用,特别是在处理页面导航和性能优化方面。

添加新评论