I'm learning redux-saga
and I'm trying to integrate it into a project that uses an API that is generated with openapi-generator which produces output like the following:
async loginUser(body: Login): Promise<LoginResponse> {
debugger;
const response = await this.loginUserRaw({ body: body });
return await response.value();
}
And loginUserRaw
is a function that performs the actual login. Then, I have the following saga:
function* login(action:Login) {
try{
const response = yield call(User.loginUser, action);
yield result(LOGIN_SUCCESS, response)
}catch(e){
yield result(LOGIN_FAILURE, e)
}
}
When this runs, I get an error in my API method's await this.loginUserRaw({ body: body });
line:
TypeError: Cannot read property 'loginUserRaw' of null
I debug it and see that this
is null. When I bind the function explicitly in the saga:
const response = yield call(User.loginUser.bind(User), action);
It works, but I don't wanna bind it every time I call a function. How can I get saga to work without explicitly binding the function? (I can't change the generated code and remove this
either)
Context in Javascript is dynamic based on the way you've written your code
const loginUser = User.loginUser
loginUser() // context lost, because there is no longer `User.` in front of it
Same applies when you pass a function as an parameter. This means that you have to provide the call
effect context in some way. The bind
method is one option, however the effect itself supports multiple ways of providing context. You can find them in the official docs https://redux-saga.js.org/docs/api/#callcontext-fn-args, here is the short version of it:
Possible ways to pass context:
call([context, fn], ...args)
call([context, fnName], ...args)
call({context, fn}, ...args)
So for example you can do the following:
const response = yield call([User, User.loginUser], action);