Jonas.D
Jonas.D

Reputation: 357

how to pass returned fetch data to a reducer using redux saga

I'm doing a fetch request that makes a new user in my database. All of it works and a new user is made/api-key returned.

The problem is that i am unable to pass the received response of my fetch request to my reduces. I'm wondering if I should call another action as a response to my successful fetch request that triggers a reducer and takes the response of the request as payload.

Or if I am able to pass the response of the fetch request to the reducer instantly. Here is my SAGA:

import { call, put, takeEvery, takeLatest, delay } from 'redux-saga/effects';
import {REGISTER} from '../redux/actions/loginAPIcall'

function* callAPIregister(){ 
    const json = yield fetch('http://spotlight-api.local/api/register', {
        method: 'POST',
        headers: {
          Accept: 'application/json',
         'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          name: 'apptest3',
          email: '[email protected]',
          password: '123456789'
        }),
      })
      .then((response) => response.json())
              .then(data => {
                  console.log(data)
              })
    yield put({type: 'REGISTER_SAGA', payload: json})
}

export function* watchAPIcall(){
    yield takeEvery(REGISTER, callAPIregister)
}

and below is my reducer:

import {REGISTER, LOGIN} from '../actions/loginAPIcall'

const initialState = {
    apiCalling: false, 
    occupation: null
}

function addAPIcall(state = initialState, action, payload){
    console.log('inside the api reducer')
    switch(action.type){
        case "REGISTER_SAGA":
            console.log('inside register_saga reducer', payload)
            return {
                apiCalling: true,
                occupation: 'REGISTER'
                }
        case LOGIN:
            return {
                apiCalling: true,
                occupation: 'LOGIN'
            }
        default:
            return state;
            }
}
export default addAPIcall

when loggin the reducer payload now it says undefined.

Upvotes: 0

Views: 4267

Answers (3)

Keshav Gera
Keshav Gera

Reputation: 11244

import { takeEvery, put, call } from "redux-saga/effects";   
import { AnyAction } from "redux";

const users = [
    {
      id: 1,
      name: "Keshav Gera",
      email: "[email protected]"
    },
    {
      id: 2,
      name: "Happy Gera",
      email: "[email protected]"
    }
  ];
  yield put(getUsersSuccess({ users }));

Upvotes: 0

Germa Vinsmoke
Germa Vinsmoke

Reputation: 3759

In my opinion, this thing will work for you. Made 'FETCH_FAILED' type well if there's any error in fetching then you can catch that error. So, make one more variable in your reducers initial_state object.

sagas.js

import { call, put, takeLatest, takeEvery } from 'redux-saga/effects';
import {REGISTER} from '../redux/actions/loginAPIcall';

function getData(payload){
    return fetch('http://spotlight-api.local/api/register', {
        method: 'POST',
        headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(payload),
    })
    .then(response => response.json())
    .then(json => json)
    .catch(error => {
      throw error;
    });
}

function* callAPIregister(){ 
  try{
    const payload = {
      name: 'apptest3',
      email: '[email protected]',
      password: '123456789'
    }
    const response = yield call(getData, payload);

    //In this please check what is the name of your data variable
    //Eg if its message then you can
    console.log(response);
    //use response: response.message
    yield put({type: 'REGISTER_SAGA', response: response})
  } catch (error){
    yield put({ type: 'FETCH_FAILED', error });
  }
}

export function* watchAPIcall(){
    yield takeEvery(REGISTER, callAPIregister)
}

In your reducer you can create a variable in initial state object and then in your 'REGISTER_SAGA' capture the data that we got from our saga

reducer.js

const initialState = {
    apiCalling: false, 
    occupation: null,
    data: []
}

case "REGISTER_SAGA":
        console.log('inside register_saga reducer', payload)
        return {
            apiCalling: true,
            occupation: 'REGISTER',
            data: action.response
        }

Upvotes: 0

Fyodor Yemelyanenko
Fyodor Yemelyanenko

Reputation: 11848

yield by itself will wait until Promise is resolved if Promise will be returned from the yielded statement. So correct callAPIregister will be

function* callAPIregister(){ 
    // yield will wait for Promise to resolve
    const response = yield fetch('http://spotlight-api.local/api/register', {
        method: 'POST',
        headers: {
          Accept: 'application/json',
         'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          name: 'apptest3',
          email: '[email protected]',
          password: '123456789'
        }),
      })
    // Again yield will wait for Promise to resolve
    const data = yield response.json()
    console.log(data)
    yield put({type: 'REGISTER_SAGA', payload: data})
}

And also I recommend to consider using call in yield statements. It is for easier unit testing

Upvotes: 1

Related Questions