【问题标题】:Recursive function in ReduxRedux 中的递归函数
【发布时间】:2020-09-02 05:52:09
【问题描述】:

尝试将引用传递给递归函数以检查 Redux 操作数据获取是否完成,但获取函数引用错误

const fetchAccountComplete = (state, accountNo) =>  { //state here is function reference
    
    return new Promise(resolve => { 
        
         (function waitForFetchComplete(state, accountNo) {
            
            const {isFetching, receivedAt} = state().account[accountNo] // getting state not a function here
            if (!isFetching) return resolve()
            setTimeout(waitForFetchComplete, 100)
        })()
        
    })
}

有没有更好的方法在 Redux 调度操作中向调用者函数返回一个承诺,以便在获取数据后,我需要在其他操作中执行一些其他逻辑。

更新 1:

应该更清楚。此请求有两个调用者,接收对帐户数据的操作。第一个调用者的指示与您的上述评论类似,因此等待完成,第二个调用者将不再进行异步调用,需要检查数据获取是否完成,因此尝试查看递归函数是否检查状态,以便承诺可以正在解决中

【问题讨论】:

    标签: javascript recursion react-redux preact


    【解决方案1】:

    您可以利用有希望的链接。 示例:

    具有三个操作,例如:IS_FETCHING、FETCH_SUCCESS、FETCH_ERROR。

    IS_FETCHING: 只会将您的状态设置为待处理(例如,可能对显示加载动画很有用)。

    FETCH_SUCCESS: 将包含获取更新状态的结果。还将清除 isUpdating 标志

    FETCH_ERROR: 将包含由于提取(应用程序或网络错误)而导致的任何可能的错误。还将清除 isUpdating 标志

    那么,你可以在应用程序级别做的是:

    dispatch({type: IS_FETCHING, payload: data});
    fetch(`https://MY-SERVER.com/?data=${data}`)
      .then(response => response.json())
      .then(json =>
         dispatch({
           type: isError(json) ? FETCH_RESULT : FETCH_ERROR,
           payload: json
         })
      );
    

    您甚至可以从动作创建者的工作中受益。 这是一个很好的指南:https://redux.js.org/advanced/async-actions

    【讨论】:

    • 感谢您的评论,应该更清楚。此请求有两个调用者,接收对帐户数据的操作。第一个调用者的指示与您的上述评论类似,因此等待完成,第二个调用者将不再进行异步调用,需要检查数据获取是否完成,因此尝试查看递归函数是否检查状态,以便承诺可以正在解决。
    • 我明白了,所以如果我理解的话,重新措辞要清楚:你有不同的组件需要相同的数据,但你需要避免两个完全相同的调用。我对吗?如果是这样,为什么不决定哪些组件需要进行调用呢?如果您无法决定(例如,您无法事先知道组件将如何使用),那么如何将调用者提取到第三个元素,让两个原始组件仅通过在存储级别显示数据来起作用?跨度>
    • @Guilhermevrs 这是一个糟糕的主意,现在您有多个组件需要协调是否进行 api 调用。或者您在一个甚至不需要它的组件中进行 api 调用。这将使您的代码不必要地复杂化,并且在需求发生变化时更难以更改。
    【解决方案2】:

    如果你有一个函数返回一个使用相同参数多次调用的 Promise,那么你可以对它进行分组,这样当它仍然有一个未解决的 Promise 并且有东西试图再次调用它时,就不会调用该函数具有相同的论点。

    这是一个例子:

    //group promise returning function
    const createGroup = (cache) => (
      fn,
      getKey = (...x) => JSON.stringify(x)
    ) => (...args) => {
      const key = getKey(args);
      let result = cache.get(key);
      if (result) {
        return result;
      }
      //no cache
      result = Promise.resolve(fn.apply(null, args)).then(
        (r) => {
          cache.done(key); //tell cache promise is done
          return r;
        },
        (e) => {
          cache.done(key); //tell cache promise is done
          return Promise.reject(e);
        }
      );
      cache.set(key, result);
      return result;
    };
    //creates a cache that will remove cached value when
    //  Promise is done (resolved or rejected)
    const createCache = (cache = new Map()) => {
      return {
        get: (key) => cache.get(key),
        set: (key, value) => cache.set(key, value),
        done: (key) => cache.delete(key),
      };
    };
    
    //function that retuns a promise
    const later = (time, value) => {
      console.log('executing later with values', time, value);
      return new Promise((r) =>
        setTimeout(() => r(value), time)
      );
    };
    //create group function with a cache that will remove
    //  cache key when promise is resolved or rejected
    const groupAndRemoveCacheOnDone = createGroup(
      createCache()
    );
    //grouped version of the later function
    const groupedLater = groupAndRemoveCacheOnDone(later);
    //testing the groped later
    groupedLater(100, 8); //first call causes console.log
    groupedLater(100, 8); //same arguments will not call later
    groupedLater(100, 8); //will not call later
    //will call later because arguments are not the same
    //  as the other calls
    groupedLater(100, 'XX');
    groupedLater(100, 8) //will not call later
      .then((value) => {
        console.log('resolved with:', value);
        //this will call later because cache value is removed
        //  after promise is resolved
        return groupedLater(100, 8);
      })
      .then(() => {
        //testing with fetchAccountComplete
        console.log(
          '***** how many times is fetchAccountComplete called *****'
        );
        const fetchAccountComplete = (state, accountNo) => {
          console.log(
            'fetchAccountComplete called with',
            accountNo
          );
          return new Promise((resolve) => {
            (function waitForFetchComplete(state, accountNo) {
              const {
                isFetching,
                receivedAt,
              } = state().account[accountNo]; // getting state not a function here
              if (!isFetching) return resolve();
              setTimeout(
                () => waitForFetchComplete(state, accountNo),
                100
              );
            })(state, accountNo);
          });
        };
        const data = {
          account: [{ isFetching: true }],
        };
        const state = () => data;
        const groupedFetchAccountComplete = groupAndRemoveCacheOnDone(
          fetchAccountComplete
        );
    
        groupedFetchAccountComplete(state, 0);
        groupedFetchAccountComplete(state, 0);
        groupedFetchAccountComplete(state, 0);
        groupedFetchAccountComplete(state, 0).then((resolve) =>
          console.log('resolved')
        );
        data.account[0].isFetching = false;
      });

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-01
      • 2013-04-21
      • 1970-01-01
      • 2010-12-23
      • 2019-09-14
      相关资源
      最近更新 更多