Как избежать двойной выборки данных при использовании реактивных перехватов

#reactjs #google-cloud-firestore #react-hooks

# #reactjs #Google-облако-firestore #реагирующие перехваты

Вопрос:

Я пытаюсь получить набор вопросов из базы данных Firestore, а затем сохранить их в локальном массиве для последующего использования в викторине. Поскольку я работаю над извлечением данных, они выполняются асинхронно. Я уже сталкивался с этим раньше, и решением был useEffect() компонент перехвата и условного рендеринга.

В настоящее время мой код выглядит следующим образом:

 var questions = [];
var collection = useRef('Planning');
var [loading, setLoading] = useState(true);  

useEffect(() => {
        if (props.track === 'Testing amp; Deployment') {
            collection.current = 'Test_Deploy';
        } else {
            collection.current = props.track;
        }

        if(questions.length !== 0){
            setLoading(false)
        } else {
            var questionSet = db.collection('Quizzes').doc(collection.current).collection('Questions')

            questionSet.withConverter(questionConverter).get().then(function(response) {
                    response.forEach(document => {
                        var question = document.data();
                        // running asynch - need to address
                        console.log('Question in')
                        questions.push(question)
                    })
            })
            setLoading(false)
        }

    }, [props.track, questions])}
 

В зависимости от того, где setLoading() находится, компонент либо вообще не будет повторно отображаться, либо будет дважды извлекать данные из Firestore. Я useCallback() пытался безрезультатно поиграть, а также увидел, что это может быть проблемой с React StrictMode .

Любые советы о том, как исправить мой код, чтобы повторно отобразить страницу после получения всех вопросов, без их двойной выборки?

Комментарии:

1. К вашему сведению, questions каждый цикл рендеринга будет сбрасываться обратно в пустой массив [] . Это должно быть частью состояния вашего компонента. Действительно ли ваш вопрос касается однократной выборки данных при монтировании компонента?

2. Да, это, вероятно, лежит в основе проблемы. До этого я пытался использовать компонент класса, но обнаружил, что обновить массив состояний сложно.

Ответ №1:

Для однократной выборки данных при монтировании компонента вы можете указать пустой массив зависимостей. Я также предлагаю переместить questions объект в состояние локального компонента. Поскольку состояние обновляется в цикле, вы должны использовать обновление функционального состояния для добавления каждого нового вопроса в массив.

 const [questions, setQuestions] = useState([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
  const questionSet = db
    .collection("Quizzes")
    .doc(collection.current)
    .collection("Questions");

  questionSet
    .withConverter(questionConverter)
    .get()
    .then(function (response) {
      response.forEach((document) => {
        const question = document.data();
        setQuestions(questions => [...questions, question]);
      });
    });

  setLoading(false);
}, []);
 

Если компоновщик жалуется на отсутствие зависимостей, вам нужно либо добавить их и поместить соответствующую условную проверку в выборку данных, либо добавить комментарий для игнорирования / отключения компоновщика для строки с массивом зависимостей, // eslint-disable-next-line react-hooks/exhaustive-deps .

Комментарии:

1. Именно то, что мне нужно было сделать. Спасибо, Дрю!

Ответ №2:

Он будет повторно отображаться при изменении или обновлении реквизита, включая props.track и questions каждый раз, когда вы вставляете в него элемент. Итак, если вы хотите избавиться от него повторно, просто удалите из useEffect like

 useEffect(() => {
        .......

}, [loading])} // remove from here and add `loading` here just
 

Комментарии:

1. Помещение простой загрузки в скобки все равно приведет к появлению предупреждения о том, что зависимости отсутствуют. Боюсь, я неправильно понимаю ваше исправление.