You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React函数式组件的嵌套函数内使用typed selector更新Redux状态

问题根因

代码报错的核心原因是违反了React Hook的调用规则:所有Hook必须在函数式组件的最顶层调用,不允许嵌套在useEffect、条件判断、普通函数内部执行。你把useTypedSelector放在了useEffect的条件分支里,所以触发了规则校验报错。

解决方案

你不需要用本地的currentUser状态做中转,直接在拿到Firebase返回的用户凭证后,调用useDispatch触发Redux的SET_USER动作即可,修改逻辑如下:

  1. 移除嵌套在useEffect里的useTypedSelector调用,将其移到组件顶层
  2. 引入useDispatch Hook,拿到Firebase用户数据后直接分发action更新Redux存储,不需要本地状态中转
  3. 可直接通过顶层调用useTypedSelector拿到的Redux用户数据做后续逻辑处理,比如修改按钮文本、权限判断等

修改后的UserAuth组件代码

import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import {
  getAuth,
  signInWithPopup,
  GithubAuthProvider,
  Auth,
} from 'firebase/auth';
import 'bulmaswatch/superhero/bulmaswatch.min.css';
import { UserData, setUser } from '../state/action-creators';
import { useTypedSelector } from '../hooks/use-typed-selector';

const UserAuth: React.FC = () => {
  // 组件顶层调用Hook,获取Redux中存储的用户信息
  const user = useTypedSelector(state => state.user);
  const dispatch = useDispatch();
  const [loginButtonText, setLoginButtonText] = useState<string>('Log In');
  const provider: GithubAuthProvider = new GithubAuthProvider();
  const auth: Auth = getAuth();

  const signinHandler = () => {
    signInWithPopup(auth, provider)
      .then(({ user: { uid, email, displayName, photoURL } }) => {
        const userPayload: UserData = {
          uid: uid,
          email: email as string,
          displayName: displayName as string,
          photoURL: photoURL as string,
        };
        // 直接分发action更新Redux存储
        dispatch(setUser(userPayload));
        // 示例:登录成功后修改按钮文本
        setLoginButtonText(`欢迎 ${displayName}`);
      })
      .catch((err) => {
        const errorCode = err.code;
        const errorMessage = err.message;
        const email = err.email;
        const credential = GithubAuthProvider.credentialFromError(err);
        console.log(err, errorCode, errorMessage, email, credential);
      });
  };

  return (
    <button className="gh-button button is-primary" onClick={signinHandler}>
      <i className="fab fa-github" />
      <strong style={{ marginLeft: '10px' }}>{loginButtonText}</strong>
    </button>
  );
};

export default UserAuth;

补充说明

如果还没定义setUser action,补一个即可:入参为UserData类型的用户数据,返回{type: ActionType.SET_USER, payload: userData}格式的action对象就行。如果觉得原生Redux样板代码太多,可以使用Redux Toolkit,它内置了Immer、action自动生成等能力,开发效率和Context API基本持平,还能保留Redux的调试工具、中间件等能力。

内容的提问来源于stack exchange,提问作者Bob Bass

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 11:54:03