You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React本地变量endOfDocument无法更新问题求助

Hey, let's break down why your endOfDocument variable gets stuck as true once set, and fix it step by step:

The Root Causes

  • endOfDocument is a plain JavaScript variable, not React state/ref: React doesn't track changes to regular let variables. When you update it, the component doesn't re-render, and the scroll event listener (created in the initial useEffect closure) keeps referencing the original stale value.
  • Incorrect event listener cleanup: You're trying to remove a brand new empty function () => {} instead of the actual scroll handler you added. This leaves the original listener attached, still using the old endOfDocument value.
  • start has the same issue: It's a plain variable, so its changes aren't tracked, and closures will hold stale versions of it.

Fix Steps

We'll refactor to use useRef for tracking endOfDocument and start (since we don't need these values to trigger UI re-renders) and fix the event handling:

1. Replace plain variables with useRef

import { useEffect, useRef, useState } from 'react';

// Inside your component:
const endOfDocumentRef = useRef(false);
const startRef = useRef(null);
const [exerciseList, setExerciseList] = useState([]);

2. Fix the scroll event listener in useEffect

Define the handler function explicitly so we can reference it for cleanup:

useEffect(() => {
  const { current } = selectScroll;
  const handleScroll = () => {
    // Access the ref's current value
    if (!endOfDocumentRef.current && current.scrollTop + current.clientHeight >= current.scrollHeight) {
      getMoreExercises();
    }
  };

  current.addEventListener('scroll', handleScroll);
  
  // Cleanup with the exact same handler
  return () => {
    current.removeEventListener('scroll', handleScroll);
  };
}, []); // Add selectScroll to dependencies if it can change

3. Update getMoreExercises to use refs

function getMoreExercises() {
  if (!endOfDocumentRef.current) {
    let ref = null;
    if (selectRef.current.value !== 'All') {
      ref = db
        .collection('exercises')
        .where('targetMuscle', '==', selectRef.current.value);
    } else {
      ref = db.collection('exercises');
    }
    ref
      .orderBy('average', 'desc')
      .startAfter(startRef.current)
      .limit(5)
      .get()
      .then((snapshots) => {
        startRef.current = snapshots.docs[snapshots.docs.length - 1];
        if (!startRef.current) {
          endOfDocumentRef.current = true;
        }
        snapshots.forEach((exercise) => {
          setExerciseList((prevArray) => [...prevArray, exercise.data()]);
        });
      });
  }
}

4. Fix the handleCategory function

Reset all relevant refs and clear the exercise list to start fresh:

function handleCategory() {
  endOfDocumentRef.current = false;
  startRef.current = null;
  setExerciseList([]); // Clear existing list before fetching new data
  getExercises(); // Fetch first page of the new category
}

Why This Works

  • useRef values persist across re-renders, and their .current property can be updated without triggering a re-render—ideal for tracking state that doesn't need to update the UI directly.
  • Storing the scroll handler in a variable lets us correctly remove it during cleanup, eliminating stale listeners.
  • Resetting refs and the exercise list ensures we start from scratch when switching categories, with endOfDocument back to false.

内容的提问来源于stack exchange,提问作者ozansozuoz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 21:37:56