Есть довольно элегантный способ сделать это. Прежде всего вам нужно создать реестр для ваших задач саги (помните, что запуск метода .run
промежуточного программного обеспечения возвращает дескриптор задачи):
export default class SagaTaskRegistry {
constructor() {
this._taskPromises = [];
}
addTask(task) {
if (!this._taskPromises) {
this._taskPromises = [];
}
this._taskPromises.push(task.done);
}
getPromise() {
return new Promise((resolve) => {
const promises = this._taskPromises;
if (!promises) {
resolve();
return;
}
this._taskPromises = undefined;
Promise.all(promises).then(resolve).catch(resolve);
}).then(() => {
const promises = this._taskPromises;
if (promises) {
return this.getPromise();
}
return undefined;
});
}
}
Когда вы добавляете новые задачи в промежуточное ПО saga с помощью .run
, вы затем вызываете registryInstance.add(taskDescriptor)
. SagaTaskRegistry
возьмет обещание для этой задачи и добавит его в массив.
Вызвав getPromise
, вы получите обещание, которое будет разрешено, когда все добавленные задачи будут завершены. Оно никогда не будет отклонено, так как вы, скорее всего, не хотите, чтобы неудачная выборка приводила к отклонению — вы все равно хотите отображать свое приложение с состоянием ошибки.
И вот как вы можете комбинировать его с redial
:
import createSagaMiddleware from 'redux-saga';
import { applyMiddleware, createStore } from 'redux';
import rootReducer from 'your/root/reducer';
import yourSaga from 'your/saga';
const sagaMiddleware = createSagaMiddleware();
const middleWare = [sagaMiddleware];
const createStoreWithMiddleware = applyMiddleware(...middleWare)(createStore);
const store = createStoreWithMiddleware(rootReducer);
const sagaTaskRegistry = new SagaTaskRegistry();
const sagaTask = sagaMiddleware.run(yourSaga);
sagaTaskRegistry.addTask(sagaTask);
match({ routes, history }, (error, redirectLocation, renderProps) => {
const locals = {
path: renderProps.location.pathname,
query: renderProps.location.query,
params: renderProps.params,
dispatch: store.dispatch,
};
trigger('fetch', components, locals);
// Dispatching `END` will force watcher-sagas to terminate,
// which is required for the task promises to resolve.
// Without this the server would never render anything.
// import this from the `redux-saga` package
store.dispatch(END);
// The `SagaTaskRegistry` keeps track of the promises we have to resolve
// before we can render
sagaTaskRegistry.getPromise().then(...)
});
Теперь компонент можно украсить простым хуком:
const hooks = {
fetch: ({ dispatch }) => {
dispatch(yourAction());
},
};
С этого момента вы можете просто использовать саги, как обычно. Это должно дать вам возможность делать то, что вы пытаетесь сделать. Вы можете дополнительно абстрагироваться от этого, чтобы обеспечить динамическую регистрацию саг в фрагментах с разделением кода и другие вещи. Реестр задач уже работает для этих вариантов использования, проверяя новые зарегистрированные задачи с момента последнего вызова getPromise
перед фактическим выполнением обещания.
person
Johannes Lumpe
schedule
03.01.2017