Zustand useStore重渲染时参数undefined问题排查求助
问题描述
登录应用并更新Zustand store后,调用loggedIn(cu)触发页面重渲染,抛出错误Uncaught TypeError: a is undefined,错误指向useAuthStore(useShallow(a => (...)))中的a在重渲染时为undefined。
Store代码
import {create} from 'zustand' import {ITRUserInfoDTO, LoginResponse} from "../itr-client"; export type UserContextValue = { credentials: LoginResponse | null, expiration: number | null, user: ITRUserInfoDTO | null } export interface AuthState extends UserContextValue { loggedIn: (ctx: UserContextValue) => void logout: () => void } export const LOGGED_OUT_USER_CONTEXT: UserContextValue = { credentials: null, expiration: null, user: null } export const useAuthStore = create<AuthState>( (set) => ({ ...LOGGED_OUT_USER_CONTEXT, loggedIn: (ctx: UserContextValue) => set((state) => set({...ctx})), logout: () => set((state) => set({...LOGGED_OUT_USER_CONTEXT,})) }));
组件代码
export default function LoginPage() { const {user, loggedIn} = useAuthStore(useShallow(a => ({user: a.user, loggedIn: a.loggedIn}))) const [searchParams, setSearchParams] = useSearchParams(); const redirectLocation = searchParams.get('redirect'); const navigate = useNavigate() const go = () => redirectLocation > 0 ? navigate(redirectLocation, {replace: true}) : navigate('/home', {replace: true}); // useEffect(() => { // if (user) { // go() // } // }) const tryLogin = useCallback((loginDTO) => { const authApi = new AuthenticationApi(); authApi.authenticate({loginDTO}) .then(loginResult => { const configuration = new Configuration({accessToken: loginResult.token}); const userInformationApi = new UserInformationApi(configuration); userInformationApi.getMe().then(me => { const cu = { credentials: loginResult, expiration: new Date().getTime() + loginResult.expiresIn, user: me, } // alert(JSON.stringify(cu)) loggedIn(cu) }).catch(e => {alert(`Error: ${JSON.stringify(e)}`); console.error(e)}); }) .catch(error => console.error('Error', error)) .finally(() => console.log("Done logging in")) }, [loggedIn, user])
问题原因
你的store中loggedIn和logout方法存在逻辑错误:在Zustand的set回调函数里嵌套调用了set,这会打乱Zustand的状态更新流程。Zustand的set函数仅接受两种参数:直接的状态对象,或一个返回状态对象的回调(该回调参数为当前状态)。嵌套调用set会导致状态更新异常,最终引发组件重渲染时useShallow接收的store状态a变为undefined。
解决方案
1. 修复Store中的状态更新逻辑
移除set的嵌套调用,直接传入状态对象或返回新状态:
export const useAuthStore = create<AuthState>( (set) => ({ ...LOGGED_OUT_USER_CONTEXT, loggedIn: (ctx: UserContextValue) => set({...ctx}), logout: () => set({...LOGGED_OUT_USER_CONTEXT}) }));
2. 优化组件逻辑
- 恢复登录成功后的页面跳转逻辑,并添加正确的依赖项:
useEffect(() => { if (user) { go() } }, [user, go])
- 移除
tryLogin中多余的user依赖(函数内部未使用该变量):
const tryLogin = useCallback((loginDTO) => { // 原有登录逻辑 }, [loggedIn])
内容的提问来源于stack exchange,提问作者mikeb
相关产品推荐
相关产品推荐

