简体   繁体   中英

Fetch data with redux saga

I have created an example for fetching data from API where I used redux-thunk . The following code is working.

In this context, I want to rewrite my code but using redux saga .

 import React from 'react'; import {createStore, applyMiddleware} from 'redux'; import ReactDOM from "react-dom"; import thunk from 'redux-thunk'; import axios from 'axios'; function App(props) { const initialState = { loading: false, data: [], error: '' }; const reducer = function (state = initialState, action) { switch (action.type) { case 'START_FETCH': return { ...state, loading: true }; case 'PROCESS_FETCH': return { ...state, loading: false, data: action.payload, error: "" }; case 'END_FETCH': return { ...state, loading: false, data: [], error: action.payload } } return state; }; const START_FETCH = 'START_FETCH'; const PROCESS_FETCH = 'PROCESS_FETCH'; const END_FETCH = 'END_FETCH'; let startFetchFun = () => { return { type: START_FETCH, loading: true } }; let processFetchFun = (users) => { return { type: PROCESS_FETCH, payload: users } }; let endFetchFun = (error) => { return { type: PROCESS_FETCH, payload: error } }; let fetchUsersWithThunk = () => { return function (dispatch) { dispatch(startFetchFun()); axios.get('https://jsonplaceholder.typicode.com/users') .then((response) => { dispatch(processFetchFun(response.data)); }) .catch((error) => { dispatch(endFetchFun(error.message)); console.log(error.message); }) } }; const store = createStore(reducer, applyMiddleware(thunk)); store.subscribe(() => { console.log(store.getState()) }); store.dispatch(fetchUsersWithThunk()); return ( <div className="main"> <h1>Redux-Thunk</h1> </div> ); } ReactDOM.render( <App/>, document.getElementById('root'));

I want to write the code above using redux saga, to understand better sagas. So, how to use redux-saga for this example? Who will be able to help me?

Redux Saga uses yield call to call promises like an api service and uses yield put to dispatch actions to the store.

The difference is about blocking and not blocking calls. Because we want to wait for the server to respond our request we will use yield call that is a blocking function. Instead of dispatching the action directly inside the generator saga uses yield put({ type: "actionName" }) . That's also useful for testing purposese.

So you should wrote your saga as following:

import {all, fork, put, call, takeLatest} from 'redux-saga/effects';

function* handleRequest (action) {
  try {
    yield put(startFetchFunc()); // dispatch the action to the store.
    const result = yiels call(apiService.users, [data to pass]); // wait for the response blocking the code execution.
    yield put(processFetchFun(result)); // dispatch the action to the store containing  the data
   } catch (e) {
    yield put(endFetchFun('Error'));
   }
}

function* watchRequest() {
   yield takeLatest({type: "START_FETCH"}, handleRequest);
}

export function* rootSaga() {
  yield all([
    fork(wathcRequest),
    // ... more watchers will be here...
  ]);
}

Congfigure you store as explained here https://redux-saga.js.org/docs/introduction/BeginnerTutorial.html

I suggest you to read the documentation more than once. It contains a lot of useful information that at first might be strange but much clearer once you understand how it works.

You will need to configure your store to use saga middleware:

import React from 'react';
import createSagaMiddleware from 'redux-saga';
import { createStore, applyMiddleware } from 'redux';
import reducer from './reducers';
import rootSaga from './sagas';
const sagaMiddleware = createSagaMiddleware();

const store = createStore(
   reducer,
   applyMiddleware(sagaMiddleware, logger),
);
sagaMiddleware.run(rootSaga); // < -- rootSaga exports all sagas in your app

Then you can convert your thunk to a saga:

import {call} from 'redux-saga/effects';

function* fetchUsersSaga(payload){
    try {
        yield call(startFetchFun());
        axios.get('https://jsonplaceholder.typicode.com/users')
        .then((response) => {
            yield call(processFetchFun(response.data));
        })
    } catch(err) {
        yield call(endFetchFun(error.message));
        console.log(error.message);
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM