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
相关产品推荐
相关产品推荐

