0

I am trying to implement redux-saga action dispatch functioning like Automated Re-fetching in the redux toolkit.

When opening the app, I dispatch some actions to fetch data from the server and update the redux store. When the user stays background and re-enters the app, depending on how long users stay long inactive, then the app would re-dispatch the action to fetch data from the server again. I can save the timestamp whenever fetching from the server and compare the time of the moment of switching from inactive to active. But if there is a well-already-made feature provided, I would definitely want to use that!

Sungpah Lee
  • 1,003
  • 1
  • 13
  • 31

1 Answers1

0

There are some libraries like saga-query that do similar thing for you as rtk-query, but as far as I can tell this lib specifically doesn't support refetch on focus out of the box.

Without any lib, it could be implemented like this:

import {delay, put, call, takeEvery, takeLeading, fork} from 'redux-saga/effects';

// Utility function to create a channel that will receive a message
// every time visibility changes
const createVisibilityChannel = () => {
    return eventChannel((emit) => {
        const handler = () => void emit(!document.hidden);
        document.addEventListener('visibilitychange', handler);
        return () => document.removeEventListener('visibilitychange', handler);
    });
};

// Works as takeLeading except it ignores actions for extra additional time
const takeLeadingWithDelay = (ms, pattern, saga, ...args) => {
    return takeLeading(pattern, function* (action) {
        yield call(saga, ...args, action);
        yield delay(ms);
    });
};

// Root saga
function* appSaga() {
    // Creates visbility channel
    const visibilityChannel = yield call(createVisibilityChannel);

    // Limits time between refetches for 1 minute
    yield takeLeadingWithDelay(60000, 'FETCH_DATA', fetchData);
    
    // Dispatches fetch action every time page becomes visible
    yield takeEvery(visibilityChannel, function* (visible) {
        if (visible) yield put({type: 'FETCH_DATA'});
    });

    // Fetches data on app start and starts the first timer
    yield put({type: 'FETCH_DATA'})
}

// Example fetching function
function* fetchData() {
    const response = yield fetch(
        'https://api.spacexdata.com/v3/launches?limit=5',
    );
    const data = yield response.json();
    console.log({data});
}

This solution assumes that the delay timer isn't specific to the page blur/focus but any refetches including the one on page focus, since in the opposite case I am not sure what the logic for the timer should be when the user switches to page too early.

Martin Kadlec
  • 4,702
  • 2
  • 20
  • 33