Очистить асин c функцию в хуке useEffect React - PullRequest
1 голос
/ 24 апреля 2020

У меня есть следующая функция useEffect, и я пытаюсь найти лучший способ ее убрать, когда компонент отключается.

Я думал, что было бы лучше следовать makeCancelable из React docs , однако код все еще выполняется, когда обещание отменено.

const makeCancelable = (promise) => {
  let hasCanceled_ = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then(
      val => hasCanceled_ ? reject({isCanceled: true}) : resolve(val),
      error => hasCanceled_ ? reject({isCanceled: true}) : reject(error)
    );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled_ = true;
    },
  };
};
//example useEffect
useEffect(() => {
  const getData = async () => {
    const collectionRef_1 = await firestore.collection(...)
    const collectionRef_2 = await firestore.collection(...)
    if (collectionRef_1.exists) {
      //update local state
      //this still runs!
    }
    if (collectionRef_2.exists) {
      //update local state
      //and do does this!
    }
  }
  const getDataPromise = makeCancelable(new Promise(getData))
  getDataPromise.promise.then(() => setDataLoaded(true))
  return () => getDataPromise.cancel()
}, [dataLoaded, firestore])

Я тоже безуспешно пытался const getDataPromise = makeCancelable(getData). Код выполняется нормально, просто не очищается правильно, когда компонент отключается.

Нужно ли также отменить две функции ожидания?

1 Ответ

1 голос
/ 24 апреля 2020

В вашей функции makeCancelable вы просто проверяете значение hasCanceled_ после того, как обещание закончилось (то есть getData уже полностью выполнено):

const makeCancelable = (promise) => {
  let hasCanceled_ = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    // AFTER PROMISE RESOLVES (see following '.then()'!), check if the 
    // react element has unmount (meaning the cancel function was called). 
    // If so, just reject it
    promise.then(
      val => hasCanceled_ ? reject({isCanceled: true}) : resolve(val),
      error => hasCanceled_ ? reject({isCanceled: true}) : reject(error)
    );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled_ = true;
    },
  };
};

Вместо этого в этом случае я бы порекомендовал вам go для более простого и более классического c решения и использовать переменную isMounted для создания требуемой логики c:

useEffect(() => {
  let isMounted = true
  const getData = async () => {
    const collectionRef_1 = await firestore.collection(...)
    const collectionRef_2 = await firestore.collection(...)
    if (collectionRef_1.exists && isMounted) {
      // this should not run if not mounted
    }
    if (collectionRef_2.exists && isMounted) {
      // this should not run if not mounted
    }
  }
  getData().then(() => setDataLoaded(true))
  return () => {
    isMounted = false
  }
}, [dataLoaded, firestore])
...