【问题标题】:NextJS + Redux Saga + SSRNextJS + Redux Saga + SSR
【发布时间】:2019-08-02 02:12:09
【问题描述】:

我们有一个项目,有一个 nextjs、redux saga、typescript 设置。 SSR 对于我们的网络应用非常重要,但我们在每个页面上也有很多相关的小部件。

这就是为什么我们的页面采用模块化方式构建的原因,其中每个小部件(每页 1-2 个)加载所需的数据。 这些小部件现在与 SEO 相关。

我的问题是,API 请求不是在服务器端发出的。现在它只返回服务器上每个小部件的 defaultState,并且只在客户端加载它们。

我已经搜索并找到了很多关于如何做到这一点的说明,但它们都依赖于 nextjs 等待“getInitialProps”方法直到它从服务器返回结果的事实。 由于该生命周期方法仅在“页面”文件夹中可用,因此对我不起作用。

此外,如果我阻止“getInitialProps”组件,则该组件永远不会真正呈现。

我们的页面结构如下:

- pages/Home
    - <HomeContainer ...> (fetches data for the main page)
        - <HomeComponent >
            - <Widget1Container ...> (fetches data)
            - <Widget2Container ...> (fetches data)

我想要的是服务器端在将页面返回给用户之前等待所有提供的请求。 由于页面上不同小部件的复杂性,不可能创建“组合”端点来获取“pages/Home”文件夹中的数据。

我知道这并不理想,但我们如何确保服务器确实发出了所有 3 个请求(homecontainer、widget1container、widget2container)并在返回之前等待那里的响应? 我想像 angular-universal 那样拥有它。等到没有打开的请求或承诺,然后才渲染。 有什么想法吗?

非常感谢任何帮助或想法。

谢谢

【问题讨论】:

    标签: reactjs redux redux-saga next.js


    【解决方案1】:

    由于你是redux sage,在getServerSideProps中,发送start信号给saga

    export const getServerSideProps = wrapper.getServerSideProps(
      async (context) => {
    
      store.dispatch(
        fetchWidgetsStart("add payload")
    );
    store.dispatch(END);
    await (store as SagaStore).sagaTask.toPromise();
    const state = store.getState();
    // I am making up the reducer name
    const widgetListState = state.widgetsList ? state.widgetList : null;
    return { props: { productListState } };
    

    } );

    saga 函数内部:

    export function* fetchWidgetsStart() {
      yield takeLatest(
        WidgetListActionTypes.WIDGET_LIST_START,
        fetchWidgetssAsync
      );
    }
    
    function* fetchWidgetsAsync(action: IFetchWidgetssStart) {
      try {
        const res: AxiosResponse<IWidget[] | []> = Promise.all([
             yield axios.get(fetchWidget1),
             yield axios.get(fetchWidget2),
             yield axios.get(fetchWidget3)
         ])
    
        yield put(fetchWidgetSuccess(res));
        
      } catch (e: any) {
        
        yield put(
          fetchWidgetFailure(
            e.response && e.response.data.detail
              ? e.response.data.detail
              : e.message
          )
        );
      }
    }
    

    Promise.all() 方法接受一个可迭代的 Promise 作为输入,并返回一个解析为输入 Promise 结果数组的 Promise。当输入的所有承诺都已解决,或者输入可迭代不包含任何承诺时,此返回的承诺将解决。它会在任何输入的 Promise 被拒绝或 non-Promise 抛出错误时立即拒绝,并会在第一个拒绝消息/错误中拒绝。

    【讨论】: