React+GraphQL+Auth0场景下,GraphQL查询前localStorage取值为undefined问题
解决GraphQL查询执行时localStorage返回undefined的问题
嘿,我来帮你搞定这个头疼的问题!你遇到的核心矛盾是GraphQL查询的初始化时机早于Auth0登录流程把user_email存入localStorage的时机,导致查询触发时拿不到有效邮箱值。下面给你几个实用的解决方案:
1. 等Auth0登录状态就绪后再渲染组件
别着急直接渲染带GraphQL查询的主组件,先确保Auth0的登录回调完成、user_email已经稳稳存在localStorage里。如果用的是Auth0 React SDK,可以借助useAuth0 hook的状态来控制渲染时机:
import { useAuth0 } from '@auth0/auth0-react'; import { useEffect } from 'react'; const MainPageWrapper = () => { const { isAuthenticated, user } = useAuth0(); // 登录成功后同步邮箱到localStorage(也可以在Auth0回调里完成这一步) useEffect(() => { if (user?.email) { localStorage.setItem('user_email', user.email); } }, [user]); // 未登录或用户信息未就绪时,显示加载态/登录入口 if (!isAuthenticated || !user) { return <div>正在验证登录状态...</div>; } // 就绪后再渲染带GraphQL查询的主组件 return <MainPage />; }; // 你的MainPage组件和GraphQL配置保持原样即可 export default graphql(USER_QUERY, { name: 'userQuery', skip: () => !localStorage.getItem('user_email'), options: () => ({ variables: { email: localStorage.getItem('user_email') } }) })(MainPage);
2. 用React状态同步localStorage值,避免直接在查询配置里读取
直接在GraphQL的options或skip里读取localStorage很容易踩时机坑,不如把邮箱存在组件状态里,状态更新时自动触发查询重新执行:
import { useState, useEffect } from 'react'; import { graphql } from 'react-apollo'; const MainPage = ({ userQuery }) => { const [userEmail, setUserEmail] = useState(localStorage.getItem('user_email')); // 监听localStorage变化,或者监听Auth0登录成功事件 useEffect(() => { // 监听localStorage的变化 const handleStorageUpdate = (e) => { if (e.key === 'user_email') { setUserEmail(e.newValue); } }; // 监听Auth0登录成功事件(需要你在登录流程里触发这个事件) const handleLoginSuccess = () => { const email = localStorage.getItem('user_email'); setUserEmail(email); }; window.addEventListener('storage', handleStorageUpdate); window.addEventListener('auth0:loginSuccess', handleLoginSuccess); return () => { window.removeEventListener('storage', handleStorageUpdate); window.removeEventListener('auth0:loginSuccess', handleLoginSuccess); }; }, []); // 组件业务逻辑... }; export default graphql(USER_QUERY, { name: 'userQuery', skip: ({ ownProps }) => !ownProps.userEmail, options: ({ ownProps }) => ({ variables: { email: ownProps.userEmail } }) })(MainPage);
3. 优化查询的skip和变量兜底逻辑
你现有的skip条件可以简化,同时给变量加个兜底,避免传undefined导致查询报错:
export default graphql(USER_QUERY, { name: 'userQuery', // 只要邮箱不存在或为无效值就跳过查询 skip: () => { const email = localStorage.getItem('user_email'); return !email || email === 'undefined'; }, options: () => { // 兜底空字符串,避免变量传undefined const email = localStorage.getItem('user_email') || ''; return { variables: { email } }; } })(Component);
4. 检查Auth0登录流程的时机
确认localStorage.setItem('user_email', authResponse.email)是在Auth0登录回调完全完成后执行的。比如用handleRedirectCallback的Promise回调,确保存完邮箱再跳主页面:
// 登录回调页面的代码 import { useAuth0 } from '@auth0/auth0-react'; const CallbackPage = () => { const { handleRedirectCallback } = useAuth0(); useEffect(() => { const processLogin = async () => { const authResult = await handleRedirectCallback(); // 确认用户邮箱存在后再存入localStorage if (authResult?.user?.email) { localStorage.setItem('user_email', authResult.user.email); } // 存完再跳转到主页面 window.location.href = '/main'; }; processLogin(); }, [handleRedirectCallback]); return <div>正在处理登录...</div>; };
这样用户进入主页面时,localStorage里已经有正确的邮箱值,查询就能正常执行了。
内容的提问来源于stack exchange,提问作者Kevin Danikowski
相关产品推荐
相关产品推荐

