React useEffect() 无限重新渲染以获得所有尽管依赖

React useEffect() infinite re-render for getting all despite dependencies

我对 React 比较陌生,但我一直在使用 useEffect 在页面加载时从数据库中获取我的所有新闻和事件。我最近尝试实现一个加载微调器,现在我似乎陷入了无限循环,但我不明白为什么。我在依赖数组中有新闻和事件,因为如果它们发生变化,那么我们需要更新显示给用户的内容。我能看到的唯一潜在问题是我正在我的状态存储中的操作中构建新闻和事件数组,但在尝试实现此功能之前我似乎没有遇到过这个问题。这可能有些愚蠢,但是有人可以帮助我吗?

前端代码:


export default observer(function NewsAndEvents() {
    const { generalStore } = useStore();
    const { getNewsAndEvents, events, news, loading } = generalStore

    useEffect(() => {
        getNewsAndEvents();
    }, [news, events]);

    return (
        <main id="newsAndEvents">
            <div className="infoContainer">
                <h1>News</h1>
                { loading ? <LoadingSpinner /> : news.map((news, index) => {
                   return <News key={`news_${index}`} title={news.title} content={news.content} />
                })}
            </div>

获取操作:


export default class GeneralStore {
  isAuthenticated: boolean = false;

  selectedEvent: Event | undefined = undefined;
  events: Event[] = [];

  selectedNews: News | undefined = undefined;
  news: News[] = [];

  loading: boolean = false;

  constructor() {
    makeAutoObservable(this);
  }

  getNewsAndEvents = async () => {
    this.loading = true;
    try {
      let response: any = await agent.newsAndEvents.list();
      if (response !== null) {
        runInAction(() => {
            this.events = [];
            this.news = [];
          response.events.forEach((item: any) => {
            let newEvent: Event = {
              id: item._id,
              date_time: item.date_time,
              name: item.name,
              description: item.description,
              price: item.price,
              type: ContentType.event,
            };
            this.events.push(newEvent);
          });
          response.news.forEach((item: any) => {
            let newNews: News = {
              id: item._id,
              title: item.title,
              content: item.content,
              type: ContentType.news,
            };
            this.news.push(newNews);
          });
          this.setLoading(false);
        });
      }
    } catch (ex) {
      console.log(ex);
      this.setLoading(false);
    }
  };
}

我正在使用 TS 和 MobX。

如果您的 getNewsAndEvents() 函数正在更新 newsevents,您的 useEffect 将 运行 无限。您需要创建一个标志来防止这种情况。

const [flag, setFlag] = useState(true);

useEffect(() => {
  if (flag) {
    getNewsAndEvents();
    setFlag(false);
  }
}, [flag]);

理想情况下 flag 也应该是全局状态,但我在这里使用了 useState 因为我不熟悉 mobx。

然后每次你想要getNewsAndEvents()到运行,你可以设置标志为真。

我认为问题是当加载结束时,它的值(true)保持不变,因为加载不是组件状态,所以如果加载结束组件不会被重新渲染,所以解决这个问题,我建议您使用 useState 钩子将加载值置于一个状态:

const [loading, setLoading] = useState(generalStore.loading);

然后您将添加一个具有 [generalStore.loading] 依赖项的 useEffect,这样它将在加载值更改后更新状态,这将使组件重新渲染:

useEffect(() => {
    setLoading(generalStore.loading);
}, [generalStore.loading]);

我不确定这个解决方案是否适合您,但我认为值得一试。