在next.js中渲染之前,如何等待复杂的redux-saga动作流程完成? [英] How to wait for complex redux-saga action flow to finish before rendering in next.js?

查看:365
本文介绍了在next.js中渲染之前,如何等待复杂的redux-saga动作流程完成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在等待一个动作流"从头到尾完成时遇到问题.该应用程序可以在客户端正常运行,但是在服务器端进行操作时,它直到结束时才结束.

为了明确起见,我同时使用了"next-redux-wrapper"和"next-redux-saga",因为当我对sagas使用更简单的流时,可以实现延迟渲染.

我认为错误主要是我完全理解(或不知道)传奇效果的方式.

为简洁起见,一些代码被省略了.

api.saga.js

const makeRequest = ({ body, url, method }) =>
  axios({ method, url: url, data: body });


export function* requestWatcher(action) {
  const { feature } = action.meta;

  try {
    const { data: response } = yield call(makeRequest, action.meta);
    yield put(apiSuccess({ response, feature }));
  } catch (error) {
    yield put(apiError({ error: error, feature }));
  }
}

export default function* apiSaga() {
  yield takeEvery(action => action.type.includes(API_REQUEST), requestWatcher);
}

smallBusiness.saga.js

function* watchApiSuccess(action) {
  yield put(
    setPositions({ positions: action.payload.positions })
  );
  yield put(setLoader({ isLoading: false, feature: SMALL_BUSINESS }));
}

function* watchApiError() {
  yield put(setLoader({ isLoading: false, feature: SMALL_BUSINESS }));
}

function* watchFetchPositions() {
  yield put(
    apiRequest({
      body: null,
      method: 'GET',
      url: SMALL_BUSINESS_URL,
      feature: SMALL_BUSINESS
    })
  );
  yield put(setLoader({ isLoading: true, feature: SMALL_BUSINESS }));
}

export default function* smallBusinessSaga() {
  yield all([
    takeLatest(`${SMALL_BUSINESS} ${API_SUCCESS}`, watchApiSuccess),
    takeLatest(`${SMALL_BUSINESS} ${API_ERROR}`, watchApiError),
    takeLatest(FETCH_POSITIONS, watchFetchPositions)
  ]);
}

rootSaga.js

export default function* rootSaga() {
  yield all([call(smallBusinessSaga), call(apiSaga)]);
}

configureStore.js

store.sagaTask = sagaMiddleware.run(rootSaga);

调用了客户端功能"watchApiSuccess",但没有调用服务器端功能.除了已经提到的生成器功能外,每个生成器功能都称为服务器端.

当我使用下面的代码示例简化流程时,应用将预先渲染服务器端.

function* watchPrefetchPositions() {
  const meta = {
    body: null,
    method: 'GET',
    url: SMALL_BUSINESS_URL,
    feature: SMALL_BUSINESS
  };

  const { data: response } = yield call(makeRequest, meta);
  yield put(setPositions({ positions: response.positions }));
}

export default function* smallBusinessSaga() {
  yield all([
    ...
    takeLatest(PRE_FETCH_POSITIONS, watchPrefetchPositions)
  ]);
}

我无法处理复杂的流水的主要问题是,萨加斯人将无法做正常化之类的事情.

解决方案

您可以使用标志来控制何时以及是否应渲染组件.这是一种通用的解决方案,用于呈现后备UI(例如微调框或文本),以等待异步进程(传奇,thunk,API服务等)完成并且组件具有呈现其自身所需的全部内容. /p>

我在这里附加了一个CodeSandBox示例,以便您可以一眼看到它的工作方式. https://codesandbox.io/embed/2586j3k1p

您会看到加载出现一会儿,直到提取数据为止.请注意,CodeSandBox正在缓存此API调用,因此您在第一次单击后几乎看不到正在加载的文本.

React路线图包括一个用于处理异步渲染功能的发行版,称为"Suspense",它针对您所描述的这种特定类型的流量问题模仿了相同的行为.在发布React Async Rendering之前,我建议使用标志.

如果您想了解更多详细信息,建议您观看丹·阿布拉莫夫:超越React 16 | JSConf冰岛2018

祝你好运

I'm having issues with waiting "one action flow" to finish from start until the end. The app works as usual in client, but while doing stuff server-side it doesn't finish until the end.

To clarify, I'm using both "next-redux-wrapper" and "next-redux-saga" properly, as I can achieve the delayed rendering when I use simpler flow with sagas.

I think the mistake is mostly how I understand (or not) saga effects altogether.

Some of the code is omitted for brevity.

api.saga.js

const makeRequest = ({ body, url, method }) =>
  axios({ method, url: url, data: body });


export function* requestWatcher(action) {
  const { feature } = action.meta;

  try {
    const { data: response } = yield call(makeRequest, action.meta);
    yield put(apiSuccess({ response, feature }));
  } catch (error) {
    yield put(apiError({ error: error, feature }));
  }
}

export default function* apiSaga() {
  yield takeEvery(action => action.type.includes(API_REQUEST), requestWatcher);
}

smallBusiness.saga.js

function* watchApiSuccess(action) {
  yield put(
    setPositions({ positions: action.payload.positions })
  );
  yield put(setLoader({ isLoading: false, feature: SMALL_BUSINESS }));
}

function* watchApiError() {
  yield put(setLoader({ isLoading: false, feature: SMALL_BUSINESS }));
}

function* watchFetchPositions() {
  yield put(
    apiRequest({
      body: null,
      method: 'GET',
      url: SMALL_BUSINESS_URL,
      feature: SMALL_BUSINESS
    })
  );
  yield put(setLoader({ isLoading: true, feature: SMALL_BUSINESS }));
}

export default function* smallBusinessSaga() {
  yield all([
    takeLatest(`${SMALL_BUSINESS} ${API_SUCCESS}`, watchApiSuccess),
    takeLatest(`${SMALL_BUSINESS} ${API_ERROR}`, watchApiError),
    takeLatest(FETCH_POSITIONS, watchFetchPositions)
  ]);
}

rootSaga.js

export default function* rootSaga() {
  yield all([call(smallBusinessSaga), call(apiSaga)]);
}

configureStore.js

store.sagaTask = sagaMiddleware.run(rootSaga);

Client-side function "watchApiSuccess" is called, but server-side it's not. Every generator function is called server-side except for the one already mentioned.

When I simplify the flow with something like the code example below, app will pre-render server-side.

function* watchPrefetchPositions() {
  const meta = {
    body: null,
    method: 'GET',
    url: SMALL_BUSINESS_URL,
    feature: SMALL_BUSINESS
  };

  const { data: response } = yield call(makeRequest, meta);
  yield put(setPositions({ positions: response.positions }));
}

export default function* smallBusinessSaga() {
  yield all([
    ...
    takeLatest(PRE_FETCH_POSITIONS, watchPrefetchPositions)
  ]);
}

The main issue I have with being unable to have complex flows is that sagas won't be able to do things like normalize and more.

解决方案

You can use flags in order to control when and if your components should render. This is a common solution for rendering a fallback UI (e.g: a spinner or a text) in order to wait until an async process (saga, thunk, API service etc) is finished and the component has all it needs to render itself.

I have attached a CodeSandBox example here so you can see how it works in a glimpse. https://codesandbox.io/embed/2586j3k1p

You can see that loading appears for a moment until the data is fetched. Note that CodeSandBox is caching this API call so you barely notice the loading text after the first click).

React road-map includes a release for a feature dealing with Async Rendering called "Suspense", which imitates the same behavior for this specific type of flow issues as you described. Until React Async Rendering will be released I recommend using flags.

If you would like more details, I recommend watching Dan Abramov: Beyond React 16 | JSConf Iceland 2018

Good Luck

这篇关于在next.js中渲染之前,如何等待复杂的redux-saga动作流程完成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆