繁体   English   中英

反应:我无法在 onScroll 函数中获取更新的状态值

[英]React: I can't get updated state values in the onScroll function

任务:我正在尝试在滚动响应时实现内容的动态加载。 我有一个onScroll函数来监听滚动事件,当页面一直向下滚动时,它将 isFetching 变量切换为 true。 isFetching === true时,执行来自useEffect的代码并加载内容。 一切正常,但我需要向onScroll添加另一个条件,该条件在加载的数据量 < 数据总量时触发。

问题:我有变量schoolResultsschoolResultsCount ,其中包含加载数据的数量和数据总量,但是滚动时它们不会更新,滚动时它们始终为 0。 我知道我可以将功能转移到useEffect或使用useEffect中的条件,一切都会按我的需要工作。 但我不明白为什么函数中没有外部变量的更新值?

谢谢您的帮助!

export default function Results(props: Props) {
   const location = useLocation();

   const [isLoading, setLoading] = useState<boolean>(false);
   const [isFetching, setFetching] = useState<boolean>(false);
   const [schoolResults, setSchoolResults] = useState<SchoolEvent[]>([]);
   const [schoolResultsCount, setSchoolResultsCount] = useState<number>(0);
   const [currentPage, setCurrentPage] = useState<number>(1);

   const { school } = props;
   const { id: schoolId } = school;


   useEffect(() => {
      setLoading(true);

      const promises = [
         getSchoolEvents(schoolId, getFilterForAllSchoolResults()),
         getSchoolEventsCount(schoolId, getFilterForAllSchoolResults())
      ];

      Promise.all(promises).then(([events, eventsCountObj]) => {
         setSchoolResults(events);
         setSchoolResultsCount(eventsCountObj.count);
         setLoading(false);
      });
   }, [location.search]);

   useEffect(() => {
      if (isFetching) {

         const queryFilter = {
            ...getFilterForAllSchoolResults(),
            skip: currentPage * LIMIT
         };

         getSchoolEvents(schoolId, queryFilter)
            .then((events) => {
               setSchoolResults([...schoolResults, ...events]);
               setCurrentPage(prevState => prevState + 1);
            })
            .finally(() => setFetching(false));
      }
   }, [isFetching]);

   useEffect(() => {
      document.addEventListener('scroll', onScroll);

      return function () {
         document.removeEventListener('scroll', onScroll);
      }
   }, []);

   const onScroll = (event: Event) => {
      const { target } = event;

      const scrollHeight = propz.get(target, ['documentElement', 'scrollHeight']);
      const scrollTop = propz.get(target, ['documentElement', 'scrollTop']);
      const windowInnerHeight = window.innerHeight;

      const isBottomOfPage = scrollHeight - (scrollTop + windowInnerHeight) < 100;

      // console.log('schoolResults', schoolResults.length); //The value is 0. Not updated. Why?
      // console.log('schoolResultsCount', schoolResultsCount); // The value is 0. Not updated. Why?

      if (isBottomOfPage /*&& schoolResults.length > schoolResultsCount*/) {
         setFetching(true);
      };
   };

   if (isLoading) {
      return <Loader />;
   }

   return (//Some JSX)
}

这是一个经典的陈旧关闭问题。

您有一个没有依赖关系的useEffect ,它在组件安装时将onScroll处理程序附加到scroll事件(并在组件卸载时将其删除)。 由于依赖数组为空,因此该函数在组件的生命周期内是相同的。

这就是问题所在,因为在第一次渲染的范围内的onScroll是一个引用空数组作为它的schoolResults的对象,因为这就是const schoolResults在第一次渲染时所持有的内容。 是的,它在随后的渲染中会有不同的值,但是这些对于正在使用的onScroll事件处理程序来说永远无法访问。

最佳解决方案可能取决于您尚未提供的组件的详细信息。 最简单的方法是用 ref 替换状态,因为 ref 与状态变量不同,在渲染之间保持相同的身份,只有它们current的属性更新(变异)。 所以你可以更换

const [schoolResults, setSchoolResults] = useState<SchoolEvent[]>([]);

const schoolResults = useRef<SchoolEvent[]>([]);

并将所有对setSchoolResults(someValue)的调用替换为schoolResults.current = someValue (同样,在您引用schoolResults以获取其值的地方,将其替换为schoolResults.current 。)这将解决陈旧的关闭问题。 (并且您必须对每个相关的状态变量执行此操作。)

然而,与状态相比,引用的缺点是更新引用不会导致重新渲染,这与状态更新不同。 因此,如果您的组件渲染的 JSX 输出中的任何内容使用isLoading ,这将无法按预期工作。

因此,在这种情况下,您将不得不使用另一种解决方案,其中涉及诚实地承认您的状态正在更新这一事实,因此您需要将事件处理函数更新为使用正确值的函数。 虽然只有几个步骤:

首先,将事件处理程序包装在useCallback中,并将您引用的所有相关状态值放入其依赖数组中:

const onScroll = useCallback(() => { /* your function goes here */, [schoolResults, schoolResultsCount, /* you possibly need other dependencies here, that are used inside your function */]};

然后将onScroll作为依赖项添加到添加滚动处理程序的useEffect中:

useEffect(() => {
  document.addEventListener('scroll', onScroll);

  return function () {
     document.removeEventListener('scroll', onScroll);
  }
}, [onScroll]);

通过确保滚动处理程序始终保存状态变量的最新值,这应该可以按您的预期工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM