Redux 中的递归函数

Recursive function in 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)
        })()
        
    })
}

有没有更好的方法 return 在 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

如果您有一个函数 returns 一个使用相同参数多次调用的 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;
  });