簡體   English   中英

如何使用 typescript、next-redux-wrapper、getServerSideProps?

[英]how to use 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 中沒有問題。 但是打字稿有問題。

我英語說的不好。 對不起..

所以想要簡單的代碼,簡單的描述。

謝謝。

以下是我看到的問題:

  1. 您將在createStore(reducer, enhancer) (state: State | undefined, action: AnyAction) => State收到錯誤,因為您的reducer不適合類型(state: State | undefined, action: AnyAction) => State 您必須使您的減速器適合這種類型。 現在的問題是您的減速器不允許stateundefined

改變

const rootReducer = (state: State, action: AnyAction) => {

const rootReducer = (state: State | undefined, action: AnyAction): State => {
  1. 您將在store.sagaTask = sagaMiddleware.run(rootSaga);行上收到錯誤store.sagaTask = sagaMiddleware.run(rootSaga); 因為 redux 創建的store對象沒有名為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(
    ({}) => {
    }
);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM