Как повторно отправить действие в Saga, например, Redux Toolkit, Автоматическая повторная выборка

Я пытаюсь реализовать диспетчер действий redux-saga, функционирующий как автоматическая повторная выборка в наборе инструментов redux.

При открытии приложения я отправляю некоторые действия для получения данных с сервера и обновления хранилища redux. Когда пользователь остается в фоновом режиме и повторно входит в приложение, в зависимости от того, как долго пользователи остаются неактивными, приложение повторно отправляет действие, чтобы снова получить данные с сервера. Я могу сохранять временную метку при загрузке с сервера и сравнивать время перехода из неактивного в активный. Но если есть уже хорошо сделанная функция, я определенно хотел бы ее использовать!

1 ответ

Есть некоторые библиотеки, такие как saga-query, которые делают для вас то же самое, что и rtk-query, но, насколько я могу видеть, эта библиотека специально не поддерживает refetch при фокусе из коробки.

Без какой-либо библиотеки это можно было бы реализовать так:

      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});
}

Это решение предполагает, что таймер задержки не является специфическим для размытия / фокуса страницы, но любых повторений, включая тот, который находится в фокусе страницы, поскольку в противоположном случае я не уверен, какой должна быть логика для таймера, когда пользователь переключается на страницу слишком рано.

Другие вопросы по тегам