React Custom Hook 中的闭包问题

Closure Issue in React Custom Hook

提问人:Maciej 提问时间:5/13/2023 更新时间:10/13/2023 访问量:182

问:

我想知道这是怎么回事。我终于将变量 curPage 移动到我的自定义钩子中的全局范围,因为闭包由于某种奇怪的原因不起作用。太好了......问题解决了,但它看起来并不优雅,我真的很担心为什么?

这个钩子负责分页,但它做什么并不重要。保存该值的变量很重要,因为它是每次函数运行时递增的值。let curPage = 1;getItems

import { useState } from 'react';

// let curPage = 1; I MOVED IT HERE AND WORKS BUT ... well

const usePagination = items => {
  const [itemsToRender, setItemsToRender] = useState(items.slice(0, 4));

  let curPage = 1;
  let maximumItems = 4;
  let totalPages = Math.ceil(items.length / maximumItems);

  //get 4 items per each page;
  const getItems = () => {
    curPage += 1;

    const min = (curPage - 1) * maximumItems;
    const max = curPage * maximumItems;

    setItemsToRender(state => state.concat(items.slice(min, max)));
  };

  return { getItems, itemsToRender, curPage, totalPages };
};

export default usePagination;

钩子在一些 React 组件函数中被调用,我立即解构返回的对象。

const { getItems, itemsToRender } = usePagination(articles);

总结一下问题:每次调用函数时,变量默认始终为 1。因此,当逻辑失败时,它将始终返回 2,例如,在每次单击中,它应该增长 - 1,2,3,4,5 等。getItemscurPagecurPage += 1;

钩子被调用一次,返回的函数被调用多次,但变量包含在自定义钩子函数体中,因此每次函数运行时都应该发生突变。getItemscurPage

我不明白这是怎么回事。我将不胜感激您的建议。提前致谢!马切伊

JavaScript ReactJS React-Hooks 闭包

评论

0赞 Konrad 5/13/2023
使用 state 或 ref。没有其他方法可以在重新渲染之间保存变量
0赞 Konrad 5/13/2023
The hook is called once- 不,每次状态更改或父级重新渲染时,都会调用钩子。

答:

0赞 Oktay Yuzcan 5/13/2023 #1

它就是 React。它重新渲染东西。这意味着当状态更新时,您的组件(即函数)在每次重新渲染时都会一次又一次地被调用。

  1. 您定义curPage = 1
  2. 然后你递增它curPage += 1
  3. 然后,通过以下方式更新状态setItemsToRender
  4. 然后你的组件重新渲染(再次执行)
  5. 再一次curPage = 1

对此的解决方案是使用 .它保留了渲染之间的更改值(由于闭包)useRef

const curPage = useRef(1)

curPage.current += 1
0赞 PhoenixPan 10/13/2023 #2

正如你所注意到的,这是一个闭包问题,这在 React 钩子中很常见。解决的办法是“打破”闭包,让函数实现改变。curPage

  1. 正如 Oktay Yuzcan 所指出的,use ,它不是闭包的一部分,因此它可以帮助函数知道闭包之外会发生什么。useRef()
let curPage = useRef(1);

const getItems = () => {
  curPage.current++;
}
  1. 用于在值更改时更新函数。useCallback()curPage
let curPage = 1;

const getItems = useCallback(() => {
  curPage++;
}, [curPage]);

对于您的情况,解决方案 1 更好,因为解决方案 2 在每次更改时都会重新创建函数,而解决方案 1 只需要维护一个简单的引用。curPage

避免闭包的另一种方法是将变量移动到内部函数,因此它不是闭包的一部分,而是函数本身的一部分。然而,这并不适合您在这里的情况。