Реакция: useContext, связанный с проблемой бесконечного цикла пользовательского хука

Я создаю приложение todolist в паре с Google Firebase для хранения моих данных. В приложении вы можете создавать проекты для упорядочивания ваших задач. Я использую useContext, чтобы мои проекты были доступны для всех компонентов моего приложения. В моем контексте используется настраиваемый перехватчик для вызова firebase при монтировании, чтобы получить проекты вошедшего в систему пользователя (или пустой массив, если у пользователя нет проектов, хранящихся в firebase).

Моя проблема в том, что мой contextProvider входит в цикл монтирования, делая новый вызов firebase для установки проектов каждый раз, когда он монтируется (даже если проекты не меняются). Контекст на самом деле работает в моем приложении, я только понял, что это был цикл, потому что я достиг максимального количества вызовов, которые могут быть сделаны в firebase по бесплатному плану за день.

Вот мой код для контекста:

import React, { createContext, useContext } from "react";
import PropTypes from "prop-types";
import { useProjects } from "../Hooks/index";

export const ProjectsContext = createContext();
export const ProjectsProvider = ({ children }) => {
  const { projects, setProjects } = useProjects();

 
  return (
    <ProjectsContext.Provider value={{ projects, setProjects }}>
      {children}
    </ProjectsContext.Provider>
  );
};

export const useProjectsValue = () => useContext(ProjectsContext);

и вот мой код для настраиваемого хука useProjects (), который вызывает firebase для получения проектов:

export const useProjects = () => {
  const [projects, setProjects] = useState([]);

  useEffect(() => {
    db.collection("projects")
      .where("userId", "==", "uBnTwu5ZfuPa5BE0xlkL")
      .orderBy("projectId")
      .get()
      .then((snapshot) => {
        const allProjects = snapshot.docs.map((project) => ({
          ...project.data(),
          docId: project.id,
        }));

        if (JSON.stringify(allProjects) !== JSON.stringify(projects)) {
          setProjects(allProjects);
        }
      });
  }, [projects]);

  return { projects, setProjects };
};

Кроме того, я вхожу в консоль в хуке и в контексте, чтобы проверить, сколько раз он вызывается, это хорошая практика или есть лучший способ проверить, сколько раз монтируется компонент?

заранее спасибо


person Vincent    schedule 02.10.2020    source источник
comment
Вы делаете setProjects внутри useEffect, а ваша зависимость - projects. Поэтому, когда проекты меняются, эффект использования запускается снова и устанавливает проекты снова, и снова, и снова.   -  person szczocik    schedule 02.10.2020


Ответы (1)


Ваш код застревает в цикле, потому что хук useEffect содержит projects в качестве зависимости. Поскольку код в useeffect обновляет projects, ваш код застревает в бесконечном цикле обновления состояния и повторного рендеринга.

Глядя на ваш код, кажется, что useEffect использует projects в операторе if

if (JSON.stringify(allProjects) !== JSON.stringify(projects)) {
   setProjects(allProjects);
}

и это похоже на то, что вам вообще не следует делать.

Вы можете observe коллекцию projects, если всегда хотите получать настоящие time обновляется, иначе ловушка useEffect должна запускаться только один раз.

useEffect использует функцию setProjects(), но она гарантированно не изменится, поэтому добавление или исключение ее из массива зависимостей хука useEffect не имеет значения.

person Yousaf    schedule 02.10.2020
comment
Спасибо, я удалил проекты из зависимостей, и это сработало - person Vincent; 02.10.2020