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
相关产品推荐
相关产品推荐

