Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/443.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 组件内的函数未接收最新版本的Redux状态以退出轮询_Javascript_Reactjs_Redux_React Redux - Fatal编程技术网

Javascript 组件内的函数未接收最新版本的Redux状态以退出轮询

Javascript 组件内的函数未接收最新版本的Redux状态以退出轮询,javascript,reactjs,redux,react-redux,Javascript,Reactjs,Redux,React Redux,我遇到了一个问题,我试图使用Redux状态通过使用if条件中的状态来停止某些轮询的执行。不幸的是,我浏览了SO的帖子和博客,但没有一篇涉及我的问题。我已检查是否正确使用MapStateTops,是否不可变地更新状态,是否使用Redux Thunk执行异步操作。我看过的一些帖子有: 在这篇文章中,我在投票方法方面得到了很好的帮助:但我想使用redux状态作为唯一的真相来源,但在我的用例中,这可能是不可能的 由于我有大量的代码,为了使实际问题的可读性,我已经缩减了代码,只包含相关方面。我很

我遇到了一个问题,我试图使用Redux状态通过使用
if
条件中的状态来停止某些轮询的执行。不幸的是,我浏览了SO的帖子和博客,但没有一篇涉及我的问题。我已检查是否正确使用MapStateTops,是否不可变地更新状态,是否使用Redux Thunk执行异步操作。我看过的一些帖子有:

在这篇文章中,我在投票方法方面得到了很好的帮助:但我想使用redux状态作为唯一的真相来源,但在我的用例中,这可能是不可能的

由于我有大量的代码,为了使实际问题的可读性,我已经缩减了代码,只包含相关方面。我很高兴发布这一切,但我希望尽可能精简这个问题

Loader.js
import { connect } from 'react-redux';
import { delay } from '../../shared/utility'
import * as actions from '../../store/actions/index';

const Loader = (props) => {
  const pollDatabase = (jobId, pollFunction) => { 
    return delay(5000)
      .then(pollFunction(jobId))  
        .catch(err => console.log("Failed in pollDatabase function. Error: ", err))
        };

  const pollUntilComplete = (jobId, pollFunction) => { 
    return pollDatabase(jobId, pollFunction)
        .then(res => {
            console.log(props.loadJobCompletionStatus) // <- always null
            if (!props.loadJobCompletionStatus) { <-- This is always null which is the initial state in reducer
                return pollUntilComplete(jobId, pollFunction);
            }
        })
        .catch(err=>console.log("Failed in pollUntilComplete. Error: ", err));
    };


  const uploadHandler = () => {
  ...
    const transferPromise = apiCall1() // Names changed to reduce code
      .then(res=> {
        return axios.post(api2url, res.data.id);
            })
      .then(postResponse=> {
        return axios.put(api3url, file)
        .then(()=>{ 
          return instance.post(api3url, postResponse.data) 
        })
      })

  transferDataPromise.then((res) => {
    return pollUntilComplete(res.data.job_id, 
      props.checkLoadTaskStatus)
        })
        .then(res => console.log("Task complete: ", res))
        .catch(err => console.log("An error occurred: ", err))
  }

return ( ...); // 

const mapStateToProps = state => {
    return {
        datasets: state.datasets,
        loadJobCompletionStatus: state.loadJobCompletionStatus,
        loadJobErrorStatus: state.loadJobErrorStatus,
        loadJobIsPolling: state.loadJobPollingFirestore
    }
}

const mapDispatchToProps = dispatch => {
  return {
    checkLoadTaskStatus: (jobId) => 
         dispatch(actions.loadTaskStatusInit(jobId))
    };
};


export default connect(mapStateToProps, mapDispatchToProps)(DataLoader);


似乎当我控制台记录props.loadJobCompletionStatus的值时,
props.loadJobCompletionStatus
始终为空,这是我的reducer中的初始状态。使用Redux开发工具,我看到状态确实更新了,所有操作都按照我的预期进行

最初,我将
props.loadJobCompletionStatus
作为
pollDatabase
的一个参数,并认为我可能创建了一个闭包,因此我删除了函数定义中的参数,以便函数能够从范围的“上层”获取结果,希望它能够获取最新的Redux状态。我不确定为什么我会留下一个陈腐的状态。这会导致if语句始终执行,从而对数据库进行无限轮询

有人能指出是什么原因造成的吗


谢谢

我很确定这是因为您在函数组件中定义了一个闭包,因此闭包在定义闭包时捕获了对现有道具的引用。请参阅,以更好地了解闭包和函数组件之间的关系


作为替代方案,您可以将轮询逻辑移出组件,并在thunk中执行它(在thunk中它可以访问
getState()
),或者使用
useRef()
钩子来获得可以随时间访问的可变值(并可能使用
useffect()
在每次重新渲染后将最新道具值存储在该参考中)。可能现有的钩子也可以做类似于
useRef()
方法的事情。

你看过redux传奇吗?是的,我用过传奇。这个代码库主要是用thunk编写的。然而,我不确定传奇故事能否解决这个问题。我认为这与尝试在同一渲染中访问更新状态更相关。我只是问了一下,因为我总是将任何与api相关的活动移动到sagas中,这对我来说非常有效。您可以使用一个特效来分派一个动作(例如startPolling),saga将拾取该动作,进行轮询,分派动作以相应地更新状态。我还将研究react-redux、useSelector和useDispatch中的新钩子,这样您就不用用connect-hoc包装组件了。我花了几个小时重新阅读了hooks文档,我想我已经找到了一些解决这个问题的方法。如果把它放到Redux中,这样它就可以在所有页面上持久化,我可以将整个内容转储到本地存储中,但我认为我的用例不允许这样做。我同意sagas是一条路要走,特别是在我看来,更复杂和更大的代码基础。我将在新项目中使用这个和/或其他一些钩子。这本书很有见地。显然,因为我处于同一渲染中,所以如果只使用React钩子,我将无法访问更新的状态。你知道Redux商店的逻辑是否相同吗?我将通过useRef钩子来了解它在这个上下文中是如何使用的。不,不管您使用的是React钩子还是与Redux相关的东西——编写的代码将在渲染时捕获现有的值。你需要一个我列出的备用进近/逃生舱口来解决这个问题。谢谢马克。这很有道理。我必须咬紧牙关,重构一些代码。谢谢你的建议。
delay.js
export const delay = (millis) => {
    return new Promise((resolve) => setTimeout(resolve, millis));
}

actions.js
...
export const loadTaskStatusInit = (jobId) => {
  return dispatch => {
      dispatch(loadTaskStatusStart()); // 
      const docRef = firestore.collection('coll').doc(jobId) 
        return docRef.get() 
        .then(jobData=>{
            const completionStatus = jobData.data().complete;
            const errorStatus = jobData.data().error;
            dispatch(loadTaskStatusSuccess(completionStatus, errorStatus))
        },
        error => {
            dispatch(loadTaskStatusFail(error));
        })
    };
}