问题
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.
回答1:
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
来源:https://stackoverflow.com/questions/55613294/how-to-wait-for-complex-redux-saga-action-flow-to-finish-before-rendering-in-nex