I want JavaScript -> TypeScript! but, so hard.
// store.js
import { applyMiddleware, createStore, compose, Store } from "redux";
import createSagaMiddleware, { Task } from "redux-saga";
import { createWrapper } from "next-redux-wrapper";
import { composeWithDevTools } from "redux-devtools-extension";
import reducer from "./reducers";
import rootSaga from "./sagas";
const configureStore = () => {
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware];
const enhancer =
process.env.NODE_ENV === "production"
? compose(applyMiddleware(...middlewares))
: composeWithDevTools(applyMiddleware(...middlewares));
const store = createStore(reducer, enhancer);
store.sagaTask = sagaMiddleware.run(rootSaga);
return store;
};
const wrapper = createWrapper(configureStore, {
debug: process.env.NODE_ENV === "development",
});
export default wrapper;
// reducers/index.ts
import { HYDRATE } from "next-redux-wrapper";
import { AnyAction, combineReducers } from "redux";
import url, { IUrlReducerState } from "./reducer_url";
import user, { IUserReducerState } from "./reducer_user";
export type State = {
url: IUrlReducerState;
user: IUserReducerState;
};
const rootReducer = (state: State, action: AnyAction) => {
switch (action.type) {
case HYDRATE:
return action.payload;
default: {
const combineReducer = combineReducers({
url,
user,
});
return combineReducer(state, action);
}
}
};
export type RootState = ReturnType<typeof rootReducer>;
export default rootReducer;
reducers/index.ts
<- Is this how you do it? I've changed it a little bit.
// pages/index.js
import { END } from "redux-saga";
import wrapper from "../store";
export const getServerSideProps = wrapper.getServerSideProps(
async (context) => {
context.store.dispatch({
type: LOAD_USER_REQUEST,
});
context.store.dispatch(END);
await context.store.sagaTask.toPromise();
}
);
I saw the official documentation, but I don't understand: https://github.com/kirill-konshin/next-redux-wrapper#getserversideprops
These codes are not problematic in JavaScript. But there's a problem with TypeScript.
Here are the issues that I see:
createStore(reducer, enhancer)
because your reducer
does not fit the type (state: State | undefined, action: AnyAction) => State
. You must make your reducer fit this type. The problem right now is that your reducer does not allow for state
to be undefined
.change
const rootReducer = (state: State, action: AnyAction) => {
to
const rootReducer = (state: State | undefined, action: AnyAction): State => {
store.sagaTask = sagaMiddleware.run(rootSaga);
because the store
object created by redux does not have a property called sagaTask
. There is another discussion about that here.Here is one solution, based on the next-redux-wrapper docs:
define a new interface for your store which includes the task
export interface SagaStore extends Store<State, AnyAction> {
sagaTask: Task;
}
replace
store.sagaTask = sagaMiddleware.run(rootSaga);
with
(store as SagaStore).sagaTask = sagaMiddleware.run(rootSaga);
replace
await context.store.sagaTask.toPromise();
with
await (context.store as SagaStore).sagaTask.toPromise();