Функция внутри компонента не получает последнюю версию Redux-состояния для выхода из опроса - PullRequest
0 голосов
/ 29 октября 2019

У меня проблема, когда я пытаюсь использовать состояние Redux, чтобы остановить выполнение некоторого опроса, используя состояние в условном выражении if. Я просмотрел сообщения SO и блогов, но, к сожалению, никто не занимался моей проблемой. Я проверил, правильно ли я использую mapStateToProps, я постоянно обновляю состояние и использую Redux-Thunk для асинхронных действий. Некоторые сообщения, на которые я смотрел:

Мне любезно помогли с методологией опроса в этом посте: Включение асинхронных действий, обещание.then() и рекурсивный setTimeout, избегая при этом «отложенного антипаттерна» , но я хотел использовать избыточное состояние в качестве единственного источника правды, но, возможно, это невозможно в моем случае использования.

У меня естьобрезать код для удобства чтения актуальной проблемы, чтобы включить только соответствующие аспекты, поскольку у меня есть большой объем кода. Я рад опубликовать все это, но хотел, чтобы вопрос был как можно более скудным.

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


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


Кажется, что когда я консольный журнал, значение props.loadJobCompletionStatus всегда пустокоторый является начальным состоянием в моем редукторе. Используя инструменты Redux-dev, я вижу, что состояние действительно обновляется, и все действия происходят так, как я ожидал.

Сначала я поместил props.loadJobCompletionStatus в качестве аргумента pollDatabase и подумал, что, возможно, создал замыкание, и поэтому я удалил аргументы в определении функции, чтобы функция получала результаты из«верхние» уровни области видимости, надеясь, что это принесет последнее состояние Redux. Я не уверен, почему я остался с устаревшей версией государства. Это приводит к тому, что мой оператор if выполняется всегда, и поэтому у меня бесконечный опрос базы данных.

Кто-нибудь может указать, что может быть причиной этого?

Спасибо

1 Ответ

0 голосов
/ 29 октября 2019

Я почти уверен, что это потому, что вы определяете замыкание в компоненте функции, и, таким образом, замыкание захватывает ссылку на существующие реквизиты в то время, когда замыкание было определено . См. Обширный пост Дана Абрамова «Полное руководство по useEffect» , чтобы лучше понять, как замыкания и функциональные компоненты связаны друг с другом.

В качестве альтернативы вы можете переместить логику опросакомпонент и выполнить его в thunk (где он имеет доступ к getState()), или использовать хук useRef(), чтобы получить изменяемое значение, к которому можно получить доступ в течение некоторого времени (и потенциально использовать useEffect() для хранения последних реквизитовзначение в этой ссылке после каждого повторного рендеринга). Вероятно, существуют существующие хуки, которые могли бы сделать что-то похожее на этот useRef() подход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...