React 自定义 Hook 中的关闭问题

问题描述 投票:0回答:2

我想知道这是怎么回事。我最终将变量 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);

总结问题:每次调用函数getItems

时,变量
curPage
默认始终为1。因此,当 
curPage += 1;
 时,它总是返回 2,因此每次点击时逻辑都会失败,例如它应该增长 - 1,2,3,4,5 等。

钩子被调用一次,返回的函数

getItems

被调用多次,但变量
curPage
包含在自定义钩子函数体内,因此每次函数运行时都应该发生变化。

我不明白发生了什么事。我会很感激你的建议。提前致谢!马切杰

javascript reactjs react-hooks closures
2个回答
0
投票
它是React。它重新渲染东西。这意味着当状态更新时,您的组件(即函数)会在每次重新渲染时被一次又一次地调用。

    您定义
  1. curPage = 1
    
    
  2. 然后你增加它
  3. curPage += 1
    
    
  4. 然后通过
  5. setItemsToRender
     更新状态
    
  6. 然后你的组件重新渲染(再次执行)
  7. 再一次
  8. curPage = 1
    
    
解决此问题的方法是使用

useRef

。它保留了渲染之间更改的值(感谢闭包)

const curPage = useRef(1) curPage.current += 1
    

0
投票
正如你所注意到的,这是一个闭包问题,它在 React hooks 中很常见。解决办法就是“打破”闭包,让函数实现

curPage

的改变。

    正如 Oktay Yuzcan 指出的那样,使用
  1. useRef()
    ,它不是闭包的一部分,因此它可以帮助函数了解闭包之外发生了什么。
let curPage = useRef(1); const getItems = () => { curPage.current++; }

  1. useCallback()
     的值发生变化时,使用 
    curPage
     更新函数。
let curPage = 1; const getItems = useCallback(() => { curPage++; }, [curPage]);
对于您的情况,解决方案 1 更好,因为每次 

curPage

 更改时,解决方案 2 都会重新创建该函数,而解决方案 1 只需维护一个简单的引用。

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

© www.soinside.com 2019 - 2024. All rights reserved.