react hook 中的闭包问题

1、在 react 中,当父组件向子组件传递一个函数的时候,那个函数中包含一个变量,state ,会产生闭包问题

上代码:

// 父组件
const uploadTable = (props) => {
  const {
    uploadingFileList,
  } = props;
  const deleteFile = (file) => {
    const fileList = uploadingFileList.filter(f => f.uid !== file.uid);
    console.log(fileList);  // []
  }
  return (
    <UploadingTable
      deleteFile={deleteFile}
      uploadingFileList={uploadingFileList}
    />
  )
}

子组件 调用 父组件 deleteFile 函数的时候,会发现 里面  uploadingFileList 为空

这种情况下,自然执行不下去了

 

经过检查,这里发生了闭包的现象,也就是说,这里的 deleteFile  函数 uploadingFileList 发生了闭包

解决1: 自然是 纯纯地把 uploadingFileList 通过 deleteFile 再传回来,但是一点逼格都没有

解决2:上代码  重点在于 使用 useRef

// 父组件
const uploadTable = (props) => {
  const {
    uploadingFileList,
  } = props;
  const uploadingFileListRef = useRef('');
  uploadingFileListRef.current = uploadingFileList;

  const deleteFile = (file) => {
    // 重点在于 使用 useRef
    const fileList = uploadingFileListRef.current.filter(f => f.uid !== file.uid);
    console.log(fileList);  // [正确有数据]
  }
  return (
    <UploadingTable
      deleteFile={deleteFile}
      uploadingFileList={uploadingFileList}
    />
  )
}

这里 就圆满地解决了 这个问题。

毕竟即使是闭包,但是闭包里面引入的终究是一个 地址,而这个地址里面的 数据变化是可以被读取到的

2、事实上,当使用 useCallback 也一样会引起闭包的问题,值得注意

不过useCallback 的话,只需要在 监听的数组里放入对应的数据即可解决

3、但是当 useState 中,调用 setXXX 的时候,可以选择朝里面传一个函数进去,函数的 参数就是 当前的 state ,这样可以避免 闭包、异步等等一系列的问题,如下:

setCurStep(cur => cur + 1);

4、当然,还有一种特殊的方法能避免 很多的闭包问题

import React, { useRef, useEffect, useState } from 'react';
let page = 1;  // 将 参数 提到 函数外面来

const App = (param) => {
  return (
    <div>
    </div>
  );
}

总结:

因为 产生闭包 就其更本,大多数 都是因为

state、props 改变了之后,会导致 当前的函数组件重新 执行

上一次 执行的 代码中,使用的就是 执行上下文中 保存的 之前的 值,而不是 现在 改变之后的结果

所以 使用 useRef 也好,将 变量拿到外面也好,都是 让函数 里面的变量是同一个

但是这样的话,变量的改变不会 让函数组件 重新执行,

useEffect(() => {
  const id = setInterval(() => {
    setCount(count + 1);
  }, 1000);
  return () => clearInterval(id);
}, []);

因此,类似于上面这样的代码,你会发现 count 只有在 第一次执行之后,就不会再 有任何改变

为什么?

因为 这里 useEffect 设置了一个 空数组的 依赖,也就是说,这个 useEffect 只会执行一次,接下来这个 函数组件继续执行的时候, 这里返回的其实是 第一次执行的结果。

也就是说,这里 setInterval 也形成了闭包,一只包着 第一次执行的结果

useEffect(() => {
  const id = setInterval(() => {
    setCount(count => count + 1);  // 改成一个函数
  }, 1000);
  return () => clearInterval(id);
}, []);

题外话:

记录一个很有意思的 问题

var a = 100;
let b = async () => {
  a = a + await 10;
  console.log('2', a);
}
b();
a ++;
console.log('1', a);

// 1 101
// 2 110

这里其实还因为 运算 过程的问题,先是 计算出了 这个表达式的一半,那就是 100,也就变成了 a = 100 + await 10

然后 计算 异步调用 之后,a = 100 + 10

 

var tmp = 100
async function test() {
    tmp = await new Promise((res) => {
        setTimeout(() => {
            res(tmp + 10)
        })
    })
    console.log(2, tmp)
}
test()
tmp++
console.log(1, tmp)
// 1 101
// 2 111

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值