【问题标题】:How to re-dispatch action in Saga like redux toolkit Automated Re-fetching如何在 Saga 中重新调度动作,如 redux 工具包自动重新获取
【发布时间】:2023-11-07 05:39:01
【问题描述】:

我正在尝试在 redux 工具包中实现 redux-saga 动作调度功能,例如自动重新获取。

打开应用程序时,我调度了一些操作以从服务器获取数据并更新 redux 存储。当用户停留在后台并重新进入应用程序时,根据用户长时间不活动的时间长短,应用程序将重新调度操作以再次从服务器获取数据。每当从服务器获取时,我都可以保存时间戳,并比较从非活动状态切换到活动状态的时间。但是如果提供了一个成熟的功能,我肯定会使用它!

【问题讨论】:

    标签: redux redux-saga redux-toolkit rtk


    【解决方案1】:

    有一些像 saga-query 这样的库可以为您做与 rtk-query 类似的事情,但据我所知,这个库具体不支持重新获取开箱即用的焦点。

    没有任何lib,可以这样实现:

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

    此解决方案假定延迟计时器并非特定于页面模糊/焦点,而是任何重新获取,包括页面焦点上的重新获取,因为在相反的情况下,我不确定当用户使用时计时器的逻辑应该是什么过早切换到页面。

    【讨论】: