How to inject dependencies ( or context ) in redux-sagas
Asked Answered
H

2

9

How do I use DI in redux-sagas. I have the following saga

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

As shown in the above code how do I inject userService into the saga, ideally I would like something like this

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

Thanks

Hardi answered 21/3, 2019 at 0:25 Comment(0)
S
33

How to inject dependencies in redux-sagas ?

How do I use DI in redux-sagas ?

You can do that with the Redux saga API, you have access to getContext and setContext methods that allow you to manage the context inside your sagas. Let's see how it works !

Inject your context

When you call createSagaMiddleware you can pass a context. Later we will see how to get your context in your sagas

Here is how to inject context in redux-saga:

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

const userService = createUserService(...);

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

sagaMiddleware.run(rootSaga);

Get your context

You can import getContext from redux-saga/effects and then call getContext with the key of the context that you want. So you will get userService in this case.

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

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

Testing

How we can test a context with redux-saga You can use redux-saga-test-plan. The goal of this library is to test our sagas.

What we want to do ?

  • Add mocked context in our tests
  • Ensure we try to get the right item in the context

With provide we give [[getContext("userService"), { loadUsers }]] that's the mocked context for userService.

With getContext we test if we get the right item in the context here: 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();
    });
});

I hope my answer help you 😊

Semidiurnal answered 7/4, 2019 at 11:55 Comment(0)
D
0
export function* loadUsers(userService) {
  userService.loadUsers()
}

elsewhere:

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

and then:

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

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

sagaMiddleware.run(
  rootSaga,
  userService
)
Denice answered 21/3, 2019 at 4:15 Comment(1)
How did you get the action now ?Semidiurnal

© 2022 - 2024 — McMap. All rights reserved.