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

Next.js中withAuth高阶组件连接Redux Store报错求助

你遇到的这个类型错误确实和Redux-Thunk的类型配置有关——TypeScript默认的Redux Dispatch类型只认标准的Action对象,不认你写的这种返回函数的thunk,所以得手动扩展类型让它支持。下面一步步给你搞定:

1. 先给Store添加上Thunk支持的类型

首先修改store.ts,明确我们的Dispatch类型可以处理thunk函数,同时补上之前漏掉的initialState传入(这在Next.js SSR场景下很重要,不然服务端和客户端状态可能不一致):

import { MakeStore } from 'next-redux-wrapper';
import { applyMiddleware, createStore } from 'redux';
import thunk, { ThunkDispatch } from 'redux-thunk';
import { rootReducer } from './reducers';
import { AnyAction } from 'redux';

export type RootState = ReturnType<typeof rootReducer>;

// 自定义Dispatch类型,让它支持Thunk
export type AppDispatch = ThunkDispatch<RootState, unknown, AnyAction>;

const makeStore: MakeStore<RootState> = (initialState?: RootState) => {
  return createStore(
    rootReducer,
    initialState,
    applyMiddleware(thunk)
  );
};

export default makeStore;

2. 修正withAuth.tsx里的类型和逻辑问题

你的代码里还有几个小坑:

  • connect的mapStateToProps写法错了,应该返回一个对象,不是直接返回用户
  • getInitialProps里调用dispatch时,TypeScript不知道这是thunk,得用我们定义的AppDispatch断言
  • 要处理原组件可能存在的getInitialProps,还要确保重定向在服务端和客户端都能生效

修改后的withAuth.tsx:

import cookies from 'js-cookie';
import { NextPageContext } from 'next';
import React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { dispatchCurrentUser } from '../actions/authActions';
import { RootState, AppDispatch } from '../store';
import { IUser } from '../types/auth';
import redirect from '../utils/redirect';

// 定义mapState和mapDispatch,让connect能正确推导类型
const mapState = (state: RootState) => ({
  currentUser: state.auth.user,
});

const mapDispatch = {
  dispatchCurrentUser,
};

// 生成连接后的组件props类型
type ConnectedPropsType = ConnectedProps<typeof connector>;

const withAuth = <T extends object>(C: React.ComponentType<T & ConnectedPropsType>) => {
  const AuthComponent = (props: T & ConnectedPropsType) => {
    return <C {...props} />;
  };

  AuthComponent.getInitialProps = async (context: NextPageContext) => {
    const { store, isServer } = context;
    if (!store) throw new Error('Store is missing in Next.js context');

    const state: RootState = store.getState();
    let currentUser: IUser | null = state.auth.user;

    if (!currentUser) {
      try {
        // 断言dispatch为AppDispatch,让TypeScript识别这是thunk
        await (store.dispatch as AppDispatch)(dispatchCurrentUser());
        // 重新获取更新后的用户状态
        currentUser = store.getState().auth.user;
      } catch (error) {
        console.log('User is not authenticated.');
        // 执行重定向,适配服务端和客户端
        redirect(context, '/login'); // 替换成你的登录页路径
      }
    }

    // 调用原组件的getInitialProps(如果有的话)
    const componentProps = typeof C.getInitialProps === 'function' 
      ? await C.getInitialProps(context) 
      : {};

    return { ...componentProps, isServer };
  };

  const connector = connect(mapState, mapDispatch);
  return connector(AuthComponent);
};

export default withAuth;

3. 给Auth Action补上正确的类型

修改authActions.ts,让thunk函数符合TypeScript的类型规范,同时注意axios的URL要加http://,不然会请求当前页面的路径:

import axios from 'axios';
import { AnyAction } from 'redux';
import { ThunkAction } from 'redux-thunk';
import { RootState } from '../store';
import { IUser } from '../types/auth';

// 定义我们的Thunk类型
type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  AnyAction
>;

export const dispatchCurrentUser = (): AppThunk<Promise<IUser>> => async (dispatch) => {
  // 这里要加上http://,不然axios会把localhost:8000当成相对路径
  const res = await axios.get('http://localhost:8000/api/user');
  dispatch({ type: 'GET_CURRENT_USER', payload: res.data });
  return res.data;
};

额外补充:重定向工具函数的实现

确保你的redirect函数能处理服务端和客户端两种场景,比如:

// utils/redirect.ts
import { NextPageContext } from 'next';
import Router from 'next/router';

export default function redirect(context: NextPageContext, target: string) {
  if (context.res) {
    // 服务端重定向:用HTTP头跳转
    context.res.writeHead(302, { Location: target });
    context.res.end();
  } else {
    // 客户端重定向:用Next.js Router
    Router.push(target);
  }
}

这样改完之后,TypeScript的类型错误应该就消失了,同时鉴权逻辑也更可靠,能适配Next.js的SSR场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 10:07:34