как использовать typescript, next-redux-wrapper, getServerSideProps?
Здравствуйте, я хочу javascript -> машинописный текст! но так тяжело..
Помогите!!!
// 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 <- Как вы это делаете? Я его немного изменил.
// 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();
}
);
Я видел официальный документ, но не понимаю. [https://github.com/kirill-konshin/next-redux-wrapper#getserversideprops]
Эти коды не вызывают проблем в JavaScript. Но есть проблема с машинописными текстами.
Я не очень хорошо владею английским языком. Сожалею..
Так что нужны простые коды, простое описание.
Благодарю.
2 ответа
Вот проблемы, которые я вижу:
- Вы получите ошибку в
createStore(reducer, enhancer)
потому что твойreducer
не подходит по типу(state: State | undefined, action: AnyAction) => State
. Ваш редуктор должен соответствовать этому типу. Проблема в том, что ваш редуктор не позволяетstate
бытьundefined
.
изменение
const rootReducer = (state: State, action: AnyAction) => {
к
const rootReducer = (state: State | undefined, action: AnyAction): State => {
- Вы получите сообщение об ошибке в строке
store.sagaTask = sagaMiddleware.run(rootSaga);
посколькуstore
объект, созданный с помощью redux, не имеет свойства, называемогоsagaTask
. Существует еще одна дискуссия о том, что здесь.
Вот одно из решений, основанное на документации next-redux-wrapper:
определите новый интерфейс для вашего магазина, который включает задачу
export interface SagaStore extends Store<State, AnyAction> {
sagaTask: Task;
}
заменить
store.sagaTask = sagaMiddleware.run(rootSaga);
с участием
(store as SagaStore).sagaTask = sagaMiddleware.run(rootSaga);
заменить
await context.store.sagaTask.toPromise();
с участием
await (context.store as SagaStore).sagaTask.toPromise();
У меня также были неудачные попытки правильно синхронизировать Redux с Next, и они, используя next-redux-wrapper, создали шаблон проекта, который в настоящее время работает и следует рекомендациям next-redux-wrapper. . Вы можете взглянуть на это:
https://github.com/felipemeriga/next-typescript-redux-template
В основном я создал оболочку следующим образом:
const thunkMiddleware = thunk.withExtraArgument({}) as ThunkMiddleware<IStoreState, AnyAction>;
// create a makeStore function
// This makeStore is needed for the wrapper, for every new page that is called, a new store with the current values will be created
const makeStore: MakeStore<IStoreState> = (context: Context) => createStore(reducers, composeWithDevTools(applyMiddleware(thunkMiddleware)));
export type ExtraArgument = {};
export type ThunkCreator<R = Promise<any>> = ActionCreator<ThunkAction<R, IStoreState, ExtraArgument, AnyAction>>;
// export an assembled wrapper
// this wrapper will be used to every page's component, for injecting the store and actions into it.
const wrapper = createWrapper<IStoreState>(makeStore, {debug: false});
export default wrapper;
Затем переопределил _app.tsx:
// For default you don't need to edit _app.tsx, but if you want to wrapper the pages with redux wrapper, you need
// to override _app.tsx with this code bellow
class MyApp extends App {
// @ts-ignore
static async getInitialProps({Component, ctx}) {
return {
pageProps: {
// Call page-level getInitialProps
...(Component.getInitialProps ? await Component.getInitialProps(ctx) : {}),
}
};
}
render() {
const {Component, pageProps} = this.props;
return (
<Component {...pageProps} />
);
}
}
export default wrapper.withRedux(MyApp);
И, наконец, внедрили в компонент index.tsx:
interface IProps {
tick: ITickState
updateAnnouncement: any
}
interface IState {}
interface IDispatchProps {
onUpdateTick: (message: string) => ITickState,
thunkAsyncFunction: () => Promise<any>;
}
type Props = IProps & IState & IDispatchProps
class App extends React.Component<Props> {
constructor(props: Props) {
super(props);
}
async componentWillUnmount(): Promise<void> {
await this.props.thunkAsyncFunction();
}
render() {
return (
<Layout title="Home | Next.js + TypeScript Example">
<h1>Hello Next.js </h1>
<p>
<Link href="/about">
<a>About</a>
</Link>
</p>
<div>
The current tick state: {this.props.tick.message}
</div>
</Layout>
);
}
}
const mapStateToProps = (state: IStoreState): {tick: ITickState} => ({
tick: getTickState(state)
});
const mapDispatchToProps = (dispatch: any): IDispatchProps => {
return {
onUpdateTick: (message: string) =>
dispatch(updateTick(message)),
thunkAsyncFunction: () => dispatch(thunkAsyncFunction())
}
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
// As the wrapper is injected in _app.tsx, for every component(page) that will interact with Redux and Thunk
// you need to place this piece of code bellow, that will get the static props from the wrapper, and inject on your
// component
export const getStaticProps = wrapper.getStaticProps(
({}) => {
}
);