Как получить доступ к функции диспетчеризации из epi c в redux-наблюдаемых - PullRequest
0 голосов
/ 28 апреля 2020

Хотелось бы узнать, есть ли в любом случае доступ к функции dispatch в Redux из epi c в redux-observables (1.2).

export const epicDownloadProfile = (action$, { dispatch }) =>
  action$.pipe(
    ofType(DOWNLOAD_INIT.getType()),
    switchMap(() =>
      from(downloadStart(dispatch)).pipe(
        map(() => DOWNLOAD_INIT()),
        catchError(err => of(DOWNLOAD_ERROR.asError(err.message)))
      )
    )
  )

Я знаю, что это не идеально, но У меня очень сложная функция, которая делает много вещей во время загрузки, поэтому мне нужно передать dispatch в downloadStart(). Redux-observables предоставляет мне объект StateObservable в качестве второго параметра epi c, он содержит состояние, но не содержит функцию диспетчеризации ... В примере { dispatch } приходит undefined. Есть ли другой способ получить к нему доступ?

1 Ответ

1 голос
/ 28 апреля 2020

Вы упомянули, что это не идеально, но для тех, кто может не прочитать ваш вопрос, я должен добавить предупреждение, что выполнение этого наводит на мысль, что то, что вы можете делать, является анти-паттерном - но не всегда! Конечно, если вы используете какую-то стороннюю библиотеку, которую не можете контролировать, и вам нужно передать ее ей, это понятный обходной путь. Только не поддавайтесь соблазну постоянно вызывать store.dispatch() вокруг своих эпосов, так как это, как правило, признак того, что вы боретесь с наблюдаемой редукцией. Конечно, в конце концов, это всего лишь совет, хе-хе:)

ОК. Итак, вот как вы можете это сделать:

redux-observable предоставляет способ внедрить зависимости в каждый epi c. Поэтому, когда вы создаете свое epicMiddleware, вы можете передать ссылку на магазин, отправку или что-либо еще.

https://redux-observable.js.org/docs/recipes/InjectingDependenciesIntoEpics.html

/* Where ever you create your store/middleware
*****************************************/
const middlewares = [];
const epicMiddleware = createEpicMiddleware({
  dependencies: {
    get store() { // or getStore() if you want
      return store;
    }
  }
});

middlewares.push(applyMiddleware(epicMiddleware));

const store = createStore(
  rootReducer,
  initialState,
  composeEnhancers(...middlewares)
);

epicMiddleware.run(rootEpic);

/* Where ever this epic is
*************************/
const epicDownloadProfile = (action$, state$, { store }) =>
  action$.pipe(                  dependencies ----^
    ofType(DOWNLOAD_INIT.getType()),
    switchMap(() =>
      from(downloadStart(store.dispatch)).pipe(
        map(() => DOWNLOAD_INIT()),
        catchError((err) => of(DOWNLOAD_ERROR.asError(err.message)))
      )
    )
  );

Есть и другие подходы также, например, экспорт вашего магазина из модуля, импорт его в ваши модули epi c. Но это может быть не очень хорошо, если вам не нужно, чтобы ваш магазин был синглтоном, делая SSR и т. Д. c.

Вот другой подход, если вы предпочитаете его, так как вы всегда должны запускать root epi c после магазин был создан в любом случае.

// Manually inject it yourself by wrapping the "root epic"
// with another function, which is basically an epic which
// defers to your root epic.
epicMiddleware.run((action$, state$) => {
  return rootEpic(action$, state$, { store });
});
...