Redux中的递归函数

问题描述

尝试传递对递归函数的引用以检查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:

应该更清楚了。此请求有两个调用方,即说帐户数据的操作。您将第一个调用者定向到类似于上面的注释,因此请等到完成为止,第二个调用者将不会再次执行异步调用,并且需要检查数据提取是否完成,因此请尝试查看具有检查状态的递归函数,以便使promise可以被解决

解决方法

您可以利用有前途的链接。 示例:

具有三个动作,例如: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

,

如果您有一个函数返回带有相同参数的多次调用的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).then((resolve) =>
      console.log('resolved')
    );
    data.account[0].isFetching = false;
  });