如何在useEffect中正确使用React Query数据设置默认工作区?
React Query获取数据后,仅首次渲染设置默认值失败
我想用React Query给组件获取数据,要求仅在组件首次渲染时设置默认值,于是尝试在useEffect里用useQuery返回的数据,但没成功,还出现了报错。
我的代码
Header组件代码
export default function Header() { . . . //Here i'm using a custom hook const { data: workSpaceArray } = useWorkspacesByUserData(onFetchWorkspaceSuccess, onFetchWorkspaceError); useEffect(() => { const defaultWorkspaceItem = workSpaceArray?.data.info.workspaces.filter(workspace => workspace.name === workSpaceArray?.data.info.default_workspace_id); localStorage.removeItem(USER_WORKSPACE); localStorage.setItem(USER_WORKSPACE, JSON.stringify(defaultWorkspaceItem[0])); setSelectedWorkspaceValue(defaultWorkspaceItem[0].name) }, []); return( ... ); }
自定义hook代码
import { useQuery, useMutation } from 'react-query' import { protectedRequest } from '../utils/axios-utils' import { ResponseHandler } from "./ResponseHandler" const fetchWorkspacesByUserId = async () => { const response = await protectedRequest({ url: '/workspace/load' }); return ResponseHandler(response); } export const useWorkspacesByUserData = (onSuccess, onError) => { return useQuery('fetch-workspaces-by-user', fetchWorkspacesByUserId, { onSuccess, onError, staleTime: 120000, }) }
问题分析
- 异步数据时机问题:你的
useEffect依赖是空数组,首次渲染时workSpaceArray还未拿到异步请求的返回值,处于undefined状态,后续访问嵌套属性和操作defaultWorkspaceItem[0]会直接抛出Cannot read properties of undefined错误。 - 匹配逻辑错误:
filter里用workspace.name === default_workspace_id,明显是逻辑错误——工作区名称和ID不可能匹配,这会导致defaultWorkspaceItem为空数组,defaultWorkspaceItem[0]自然不存在。
解决方案
方案一:利用React Query的onSuccess回调(推荐)
既然自定义hook已经支持传入onSuccess,直接在这个回调里处理默认值设置是最合理的:onSuccess会在数据成功获取后触发,结合staleTime配置,数据新鲜时不会重复执行,完美符合“首次渲染设置”的需求。
修改Header组件:
export default function Header() { const onFetchWorkspaceSuccess = (data) => { // 修正匹配逻辑:用工作区ID和默认ID对比 const defaultWorkspaceItem = data.info.workspaces.filter( workspace => workspace.id === data.info.default_workspace_id ); // 先判断匹配结果是否存在,避免报错 if (defaultWorkspaceItem[0]) { localStorage.removeItem(USER_WORKSPACE); localStorage.setItem(USER_WORKSPACE, JSON.stringify(defaultWorkspaceItem[0])); setSelectedWorkspaceValue(defaultWorkspaceItem[0].name); } }; const onFetchWorkspaceError = (error) => { console.error('加载工作区失败:', error); // 可添加用户提示逻辑 }; const { data: workSpaceArray } = useWorkspacesByUserData(onFetchWorkspaceSuccess, onFetchWorkspaceError); return( // ... 组件原有内容 ); }
方案二:给useEffect添加正确依赖(可选)
如果一定要用useEffect,需要添加workSpaceArray作为依赖,并增加数据存在性判断,同时可以加状态标记避免重复执行:
export default function Header() { const { data: workSpaceArray } = useWorkspacesByUserData(onFetchWorkspaceSuccess, onFetchWorkspaceError); const [isDefaultSet, setIsDefaultSet] = useState(false); useEffect(() => { // 已设置过默认值,或数据未加载完成时直接返回 if (isDefaultSet || !workSpaceArray?.data?.info) return; // 修正匹配逻辑 const defaultWorkspaceItem = workSpaceArray.data.info.workspaces.filter( workspace => workspace.id === workSpaceArray.data.info.default_workspace_id ); if (defaultWorkspaceItem[0]) { localStorage.removeItem(USER_WORKSPACE); localStorage.setItem(USER_WORKSPACE, JSON.stringify(defaultWorkspaceItem[0])); setSelectedWorkspaceValue(defaultWorkspaceItem[0].name); setIsDefaultSet(true); // 标记已完成设置,避免后续重复执行 } }, [workSpaceArray, isDefaultSet]); return( // ... 组件原有内容 ); }
关键注意事项
- 必须修正
filter的匹配逻辑,用workspace.id和default_workspace_id对比,否则无法找到目标工作区。 - 任何时候访问嵌套对象前都要做存在性判断,避免因数据未加载完成导致的报错。
内容的提问来源于stack exchange,提问作者Deshan-Charuka
相关产品推荐
相关产品推荐

