如何在useEffect中调用RTK Query获取登录用户的购物车数据
问题根因
报错的核心原因是违反了React的Hook调用规则:所有Hook必须在组件的顶层作用域调用,不能嵌套在useEffect、条件判断、普通函数内部。useGetCartByIDQuery本身是RTK Query生成的自定义Hook,放在useEffect的条件分支里自然无法正常运行。同时你原有useEffect的依赖写的是dispatch,dispatch是稳定引用永远不会变化,会导致这个effect只会在组件首次挂载时执行一次,监听不到登录后的用户数据更新。
解决方案
方案1(推荐):使用skip参数控制请求(符合RTK Query设计规范)
直接把Query移到组件顶层,通过skip参数控制是否发起请求,不需要手动写useEffect触发:
const Login = () => { const user = useAppSelector(state=> state.auth); const dispatch = useAppDispatch(); const [login] = useLoginMutation(); const [showPassword,setShowPassword] = useState<boolean>(false); // Query移到组件顶层,用skip控制请求时机 const {data: cartData, isLoading: cartLoading, isFetching: cartFetching }= useGetCartByIDQuery(user?.user?._id!, { // 用户不存在/没有用户ID时跳过请求 skip: !user?.user?._id }) // 如果需要把购物车数据存入你的UserCartData slice,加这个effect同步即可 useEffect(() => { if(cartData){ dispatch(setCartData(cartData)) // 替换为你自己的购物车slice更新方法 } }, [cartData, dispatch]) return ( <Container> <Wrapper> <Title>SIGN IN</Title> <Formik initialValues={{ email: "", password: "" }} validationSchema={Yup.object({ password: Yup.string() .min(8, 'Must be 8 characters or higher') .required(), email: Yup.string().email('Invalid email address').required(), })} onSubmit = { async (values, actions) => { try{ const result = await login(values); if("data" in result){ dispatch(setCredentials({user:result.data.data.findUser,token:result.data.data.cookie})) }else{ const err = (result.error as RequestError).data.message if(err.includes("password")){ actions.setErrors({password:err}) }else if(err.includes("Facebook")){ actions.setErrors({email:err}) } } }catch(err){ console.log(err) } }}> {/* 其余原有代码 */}
RTK Query会自动在skip变为false的时候发起请求,同时内置缓存、加载状态管理,不需要额外维护购物车相关状态。
方案2:使用懒加载Query手动触发
如果你需要完全手动控制请求触发时机,可以用RTK Query自动生成的lazy版本Query:
const Login = () => { const user = useAppSelector(state=> state.auth); const dispatch = useAppDispatch(); const [login] = useLoginMutation(); const [showPassword,setShowPassword] = useState<boolean>(false); // 用懒加载Query拿到触发函数 const [triggerGetCart, {data: cartData, isLoading: cartLoading}] = useLazyGetCartByIDQuery(); // 监听user变化,存在时手动触发请求 useEffect(() => { if (user?.user?._id){ triggerGetCart(user.user._id) } }, [user, triggerGetCart]) // 同步购物车数据到slice的逻辑和方案1一致 useEffect(() => { if(cartData){ dispatch(setCartData(cartData)) } }, [cartData, dispatch]) // 其余原有代码不变
内容的提问来源于stack exchange,提问作者Kai021195
相关产品推荐
相关产品推荐

