文章目录

React自定义Hook如何正确封装可复用的状态逻辑

发布于 2026-05-10 05:23:06 · 浏览 15 次 · 评论 0 条

React自定义Hook如何正确封装可复用的状态逻辑

自定义Hook是React中复用组件逻辑的重要方式。通过将状态和副作用逻辑封装成可复用的函数,可以避免组件间重复代码,保持代码整洁。


一、自定义Hook的基本规则

自定义Hook必须以 use 开头,这是React识别Hook的约定。它返回一个数组或对象,包含状态和操作函数。

// 正确的自定义Hook命名
function useMyLogic() {
  // 逻辑实现
  return [state, setState];
}

二、创建自定义Hook的步骤

1. 识别 可复用的逻辑

在现有组件中寻找重复的状态管理或副作用逻辑。例如,多个组件都需要获取数据或处理表单输入。

2. 提取 逻辑到独立函数

将重复逻辑从组件中移出,创建新的函数。确保函数只包含状态和副作用,不包含UI渲染。

// 示例:提取数据获取逻辑
function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch(url)
      .then(response => response.json())
      .then(setData)
      .catch(setError)
      .finally(() => setLoading(false));
  }, [url]);

  return { data, loading, error };
}

3. 返回 状态和操作函数

根据需要返回状态值、操作函数或对象。确保返回值清晰,便于调用组件使用。

4. 在组件中 使用自定义Hook

像使用内置Hook一样调用自定义Hook,获取返回的状态和函数。

function UserProfile({ userId }) {
  const { data, loading, error } = useFetch(`/api/users/${userId}`);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return <div>{data.name}</div>;
}

三、最佳实践

1. 参数化 逻辑

通过参数使Hook更灵活,适应不同场景。

function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      return initialValue;
    }
  });

  const setValue = value => {
    try {
      setStoredValue(value);
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.error(error);
    }
  };

  return [storedValue, setValue];
}

2. 管理 依赖关系

在useEffect中正确声明依赖数组,避免不必要的重新执行。

useEffect(() => {
  // 依赖url和options
}, [url, options]);

3. 保持 纯净

自定义Hook不应包含UI渲染逻辑,只处理状态和副作用。

4. 测试 Hook

编写单元测试确保Hook行为正确,使用React Testing Library或Jest。

test('useFetch fetches data', async () => {
  global.fetch = jest.fn(() =>
    Promise.resolve({
      json: () => Promise.resolve({ name: 'Test' })
    })
  );

  const { result, waitForNextUpdate } = renderHook(() => useFetch('/api/test'));

  expect(result.current.loading).toBe(true);
  await waitForNextUpdate();
  expect(result.current.data).toEqual({ name: 'Test' });
});

四、常见场景示例

1. 表单处理Hook

function useForm(initialValues) {
  const [values, setValues] = useState(initialValues);

  const handleChange = e => {
    const { name, value } = e.target;
    setValues(prev => ({ ...prev, [name]: value }));
  };

  const resetForm = () => setValues(initialValues);

  return [values, handleChange, resetForm];
}

2. 窗口尺寸Hook

function useWindowSize() {
  const [size, setSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight
  });

  useEffect(() => {
    const handleResize = () => setSize({
      width: window.innerWidth,
      height: window.innerHeight
    });

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return size;
}

通过遵循这些步骤和最佳实践,可以创建出高效、可复用的自定义Hook,提升React应用的代码质量和开发效率。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文