Skip to content

react hook 与 闭包

仲灏2022-07-31约 1 分钟

<div style="display: none;" hidden="true" aria-hidden="true" data-nosnippet>Are you an LLM? You can read better optimized documentation at /pages/6a4091.md for this page in Markdown format</div>

闭包

简单来说就是上级作用域内变量的生命周期,因为被下级作用域内引用,而没有被释放。就导致上级作用域内的变量,等到下级作用域执行完以后才正常得到释放。

具体搜索看我《javascript》文章

tsx
import React, { useEffect, useState } from "react";

const testClosure = () => {
  let num = 0;

  const effect = () => {
    num += 1;
    const message = `num value in message:${num}`;

    return function unmount() {
      console.log(message);
    };
  };

  return effect;
};
// 执行test,返回effect函数
const add = testClosure();
// 执行effect函数,返回引用了message1的unmount函数
const unmount = add();
// 再一次执行effect函数,返回引用了message2的unmount函数
add();
// message3
add();
// message4
add();
// message5
add();
unmount(); // 在这里会打印什么呢?按照直觉似乎应该打印3,实际上打印了1

// react hook 与 闭包,hook 与 闭包经典的坑
export const Test = () => {
  const [num, setNum] = useState(0);

  const add = () => setNum(num + 1);

  useEffect(() => {
    const id = setInterval(() => {
      console.log("num in setInterval:", num);
    }, 1000);
    return () => clearInterval(id);
  }, [num]);

  useEffect(() => {
    return () => {
      console.log("卸载值:", num);
    };
  }, [num]);

  return (
    <div>
      <button onClick={add}>add</button>
      <p>number: {num}</p>
    </div>
  );
};

结果始终输出的为1

react hook 闭包

react
import React, { useEffect, useState } from "react";

export const Test = () => {
  const [num, setNum] = useState(0);

  const add = () => {
    console.log("num is addEvent:", num);
    setNum(num + 1);
  };

  useEffect(() => {
    setInterval(() => {
      console.log("num is setInterval:", num);
    }, 1000);

    return () => {
      console.log(num);
    };
  }, []);

  return (
    <div>
      <button onClick={add}>add</button>
      <p>{num}</p>
    </div>
  );
};

image-20220731102329660

可以看到 use Effect 在最初执行的时候引用的初始值0,形成了闭包。在后续页面如何加载都不会影响到结果。

使用更新的值

若想想要实时输出变化后的值,需要传入监听值,值变化后重新执行其内的代码 记得清楚定时器

tsx
  useEffect(() => {
    const interval = setInterval(() => {
      console.log("num is setInterval:", num);
    }, 1000);

    return () => {
      clearInterval(interval);
      console.log(num);
    };
  }, [num]);

使用useRef 使用初始值