• AJAX POLLING IN REDUX PART 2: SAGAS
  • By Josh M
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: Liu Jiayi
  • Proofreader: Yoyoyohamapi, FateZeros

Not long ago I wrote a short article on using AJAX polling in React, which can be summarized as how to initiate and control periodic AJAX requests. I’ve shown that native React and Redux are technically sufficient to solve AJAX polling control problems by using a component lifecycle approach. Over time, I found in using this method need developers very careful screening and management componentWillReceiveProps incoming props. Eventually, my goal became to remove as much asynchronous logic from components as possible.

In the Redux ecosystem, there are libraries for managing side effects, from the basic Redux-Thunk, to the elm-inspired Redux-loop, and finally redux-Saga, which is powered by Generator functions.

Ideally, I like to put all asynchronous requests into one API middleware, as can be seen from the official Redux example, the Real World example. Using thunk would pollute my Action creation function with asynchronous logic, so redux-thunk is out. Using redux-loop would conflict with my middleware, which is an enhancer of the Store but modifies the Store’s signature, causing all of its downstream middleware to need to be tweaked. So I decided to explore Redux-Saga, which essentially gives me the ability to perform tasks in the background of an app. Using Redux-Saga allows me to centrally control the use of asynchronous logic with middleware, while setting up various watchers to trigger side effects. So how do you use Redux-Sage to handle AJAX polling?

// Utility function for delayed side effectsfunction delay(millis) {  
    const promise = new Promise(resolve => {
        setTimeout(() => resolve(true), millis)
    });
    returnpromise; } // Get data every 20 secondsfunction* pollData() { try { yield call(delay, 20000); yield put(dataFetch()); } catch (error) {// Cancel the exception -- you can catch it if you wishreturn; }} // After the last data request is returned successfully, the next round of polling is initiated. // If the user logs out, the unfinished polling is cancelledfunction* watchPollData() {  
    while (true) { yield take(DATA_FETCH_SUCCESS); yield race([ call(pollData), take(USER_LOGOUT) ]); }} // Let various tasks run in parallel in the backgroundexport default function* root() {yield [fork(watchPollData) // Other observers may be included here]; }Copy the code

This polling logic in the form of SAGas frees developers from dealing with potentially complex lifecycles in components. I added the USER_LOGOUT Action to the Race condition to override the clearTimeout in componentWillUnmount. The running pollData Saga can be nicely interrupted when the logout Action is sent.

The remaining logic involved is as follows:

DataFetch – This is an Action creation function that generates actions that are intercepted and processed by THE API middleware. The actual API request is made in the middleware and a series of subsequent actions are issued based on the result of the request.

WatchPollData – This is a saga that starts with the application and runs all the time. Once started, it blocks saga execution and listens for the DATA_FETCH_SUCCESS Action to be issued. Once it hears that the corresponding Action has been issued, it unblocks and continues with the subsequent pollData saga.

PollData – Block the execution of the Generator function, call the dataFetch 20 seconds later and dispatch the Action generated by the dataFetch.

The take, PUT, race, call, and fork operators used here can be found in Redux-saga documentation.

You can compare the new approach in this article to the control within components approach in the previous article, which is much better at predicting and centrally managing my side effects with Saga. Note that not all browsers support Generator functions, and if you are using ES2015 and Babel, they already provide browser Polyfill compatibility for Generator functions.

Now all the data containers (components) simply call dataFetch() once at mount time, and our Saga automatically takes over all the polling. Very simple and beautiful.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.