You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React MVVM架构下useEffect缺失依赖警告的优雅解决方法咨询

你遇到的问题本质是ViewModel提供的getUsersList函数在组件每次渲染时可能生成新的引用,导致添加到useEffect依赖后触发无限循环,而ESLint的依赖检查又要求你声明它。下面是几个优雅的解决方案:

解决方案1:在ViewModel中用useCallback稳定函数引用

如果你的ViewModel是通过自定义Hook实现的,直接在ViewModel内部用useCallback包裹getUsersList,确保只有当它依赖的核心变量变化时才重新生成函数引用。

示例代码:

// useUserViewModel.js
import { useCallback, useState } from 'react';
import api from './api';

export function useUserViewModel() {
  const [users, setUsers] = useState([]);

  // 用useCallback包裹,依赖数组只放api和setUsers(这两个通常是稳定引用)
  const getUsersList = useCallback(async () => {
    const response = await api.get('/users');
    setUsers(response.data);
  }, [api, setUsers]);

  return { users, getUsersList };
}

// UserListView.jsx
import { useEffect } from 'react';
import { useUserViewModel } from './useUserViewModel';

export function UserListView() {
  const { users, getUsersList } = useUserViewModel();

  // 此时getUsersList是稳定引用,添加到依赖不会触发无限循环
  useEffect(() => {
    getUsersList();
  }, [getUsersList]);

  return (
    <div>
      {users.map(user => <div key={user.id}>{user.name}</div>)}
    </div>
  );
}

这个方案是最推荐的,因为它从源头稳定了函数引用,既满足ESLint要求,又避免了无限循环,同时符合ViewModel封装逻辑的设计。

解决方案2:用useRef缓存最新函数引用

如果ViewModel无法修改(比如是第三方库或类实现的),可以在组件内部用useRef保存getUsersList的最新引用,这样useEffect的依赖数组不会变化,但每次调用时都能拿到最新的函数。

示例代码:

// UserListView.jsx
import { useEffect, useRef } from 'react';
import { useUserViewModel } from './useUserViewModel';

export function UserListView() {
  const { users, getUsersList } = useUserViewModel();
  const getUsersRef = useRef(getUsersList);

  // 每次渲染更新ref的current,确保拿到最新的getUsersList
  useEffect(() => {
    getUsersRef.current = getUsersList;
  }, [getUsersList]);

  // useEffect依赖空数组,只在挂载时调用,但用ref里的最新函数
  useEffect(() => {
    getUsersRef.current();
  }, []);

  return (
    <div>
      {users.map(user => <div key={user.id}>{user.name}</div>)}
    </div>
  );
}

这个方案适合无法修改ViewModel的场景,但要注意如果getUsersList依赖的变量在组件渲染中变化,ref会同步更新,确保调用的是最新逻辑。

解决方案3:使用React 18+的useEvent(实验性API)

React 18提供了useEvent API(目前是实验性的,需通过react-experimental导入),它可以创建一个稳定引用的函数,内部始终能访问到最新的props和state,完美解决这种函数依赖导致的循环问题。

示例代码:

// UserListView.jsx
import { useEffect, useEvent } from 'react';
import { useUserViewModel } from './useUserViewModel';

export function UserListView() {
  const { users, getUsersList } = useUserViewModel();

  // 用useEvent包裹,生成稳定引用的函数
  const stableGetUsers = useEvent(() => {
    getUsersList();
  });

  useEffect(() => {
    stableGetUsers();
  }, [stableGetUsers]); // stableGetUsers是稳定引用,不会触发循环

  return (
    <div>
      {users.map(user => <div key={user.id}>{user.name}</div>)}
    </div>
  );
}

注意:useEvent目前是实验性特性,正式项目使用前要确认React版本和相关配置,未来可能会成为正式API。

内容的提问来源于stack exchange,提问作者Matos2802

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 07:02:16