Как внедрить зависимости (или контекст) в redux-sagas

#javascript #design-patterns #dependency-injection #redux #redux-saga

#javascript #шаблоны проектирования #внедрение зависимостей #redux #redux-saga

Вопрос:

Как мне использовать DI в redux-sagas. У меня есть следующая сага

 export function* loadUsers() {
  // Want to use something like userService.loadUsers()
}
  

Как показано в приведенном выше коде, как мне внедрить UserService в saga, в идеале я хотел бы что-то вроде этого

 export function* loadUsers(userService) {
   userService.loadUsers()
}
  

Спасибо

Ответ №1:

Как внедрить зависимости в redux-sagas?

Как мне использовать DI в redux-sagas?

Вы можете сделать это с помощью API Redux saga, у вас есть доступ к getContext и setContext методам, которые позволяют вам управлять контекстом внутри ваших саг. Давайте посмотрим, как это работает!

Внедрите свой контекст

При вызове createSagaMiddleware вы можете передать контекст. Позже мы увидим, как получить ваш контекст в ваших sagas

Вот как внедрить контекст в redux-saga:

 import { createUserService } from "...";
import createSagaMiddleware from "redux-saga";

const userService = createUserService(...);

const sagaMiddleware = createSagaMiddleware({
    context: {
        userService
    }
});

sagaMiddleware.run(rootSaga);
  

Получите ваш контекст

Вы можете импортировать getContext из redux-saga / effects, а затем вызвать getContext с ключом нужного вам контекста. Таким образом, вы получите userService в этом случае.

 import { getContext } from "redux-saga/effects";

export function* loadUsersSagas(action) {
    const userService = yield getContext("userService");
    const users = yield userService.loadUsers();
    ...
}
  

Тестирование

Как мы можем протестировать контекст с помощью redux-saga Вы можете использовать redux-saga-test-plan. Цель этой библиотеки — протестировать наши саги.

Что мы хотим сделать?

  • Добавляйте поддельный контекст в наши тесты
  • Убедитесь, что мы пытаемся получить правильный элемент в контексте

С помощью provide мы приводим [[getContext("userService"), { loadUsers }]] это издевательский контекст для userService .

С помощью getContext мы проверяем, получаем ли мы правильный элемент в контексте здесь: userService

 import { getContext } from "redux-saga-test-plan/matchers";

describe("Load users", () => {
    it("should load mocked users", () => {
      const loadUsers = () => Promise.resolve([johnDoe]);
      const action = createAction(...);

      return expectSaga(loadUsersSagas, action)
        .provide([[getContext("userService"), { loadUsers }]])
        .getContext("userService")
        .call(...)
        .put(...)
        .run();
    });
});

  

Я надеюсь, что мой ответ поможет вам 😊

Ответ №2:

 export function* loadUsers(userService) {
  userService.loadUsers()
}
  

в другом месте:

 export default function* rootSaga(userService) {
  yield all([
    ...,
    ...,
    loadUsers(userService)
  ]);
}
  

и затем:

 import { createUserService } from "...";
import createSagaMiddleware from "redux-saga";

const userService = createUserService(...);
const sagaMiddleware = createSagaMiddleware();

sagaMiddleware.run(
  rootSaga,
  userService
)
  

Комментарии:

1. Как вы получили действие сейчас?