Итак, я пытаюсь сделать экран загрузки с помощью response и firebase firestore. По сути, я хочу создавать загрузчик всякий раз, когда мое приложение получает данные из firestore.

РЕДАКТИРОВАТЬ: Например, я попытался сделать что-то вроде:

const [data, setData]=useState([])
const [loader, setLoader]=useState(false)


db.collection('conversations').doc(id).onSnapshot(snap=>{
setData(snap.data())
}).then(()=>{
setLoader(true)
})

Но это установит для загрузчика значение true, но я хочу установить для загрузчика значение true до того, как данные будут доступны и когда они будут извлечены, я хочу установить для загрузчика значение false.

Какие-либо предложения?

1
Joshua Bitton 11 Фев 2021 в 04:05

1 ответ

Лучший ответ

.onSnapShot() не делает то, что вы думаете - он присоединяет прослушиватель для изменений в документе, который всегда срабатывает хотя бы один раз, а затем для любых дальнейших изменений - но не обязательно сразу. ! Он также НЕ возвращает обещание; он возвращает функцию отказа от подписки - полезно, когда является частью ловушки useEffect.

В вашем коде происходит то, что слушатель прикреплен, затем setLoader(true) немедленно вызывается - из-за цикла событий Javascript, задолго до того, как функция слушателя вообще сможет быть вызванным.

ЕСЛИ вы запланировали, что setLoader(true) будет вызываться после возврата данных, как минимум вам потребуется:

db.collection('conversations').doc(id).onSnapshot(snap=>{
setData(snap.data())
setLoader(true)
})

Я отмечу, что это само по себе НЕ имеет дело с возможными ошибками из снимка.

Скорее всего, это часть ловушки useEffect, которая поможет размонтировать слушатель, когда компонент размонтирован.

useEffect(() => {
  return db
  .collection('conversations')
  .doc(id)
  .onSnapshot(snap=>{
    setData(snap.data());
    setLoader(true)
  })
}, []);

ЕСЛИ , otoh, вы просто хотите получить документ один раз, вы захотите использовать .get (), который действительно возвращает обещание с DocumentSnapshot

db.collection('conversations').doc(id).get().then(snap=>{
setData(snap.data())
}).then(()=>{
setLoader(true)
})

И, как указано в комментарии, для одной выборки:

useEffect(() => {
  // no need for a return for a single get
  setLoader(true)
  db
  .collection('conversations')
  .doc(id)
  .get()
  .then(snap=>{
    setData(snap.data());
    setLoader(false);
  })
}, [*whatever state variable will change to start the process*]);

... а для слушателя (см. выше) используйте совершенно другой подход:

const [data, setData]=useState([])
const [loader, setLoader]=useState(true) //DEFAULTS TO LOADING

useEffect(() => {
  return db
  .collection('conversations')
  .doc(id)
  .onSnapshot(snap=>{
    setData(snap.data());
    setLoader(false) //when the data is ready THE FIRST TIME
  })
}, []);

Нет необходимости делать что-либо, чтобы установить состояние LOADING для любых обновлений со стороны слушателя - это будет обрабатываться с помощью управления состоянием и setData (). Изменения будут отображаться при последующем рендеринге каждый раз, когда Firestore вызывает слушателя.

2
LeadDreamer 12 Фев 2021 в 01:41