添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
没有腹肌的自行车  ·  以 React + Express ...·  2 天前    · 
善良的稀饭  ·  合成事件 – React·  2 天前    · 
好帅的饺子  ·  [框架課程] React 19 ...·  2 天前    · 
含蓄的山楂  ·  Unit Testing: Test ...·  7 月前    · 
坚韧的凉面  ·  Django_filters ...·  8 月前    · 
  • 第一次初始化以后,没有任何事情能引起它的再次渲染(因为没有父组件、没有状态/props改变),所以只会渲染一次
  • 因为只渲染一次,value也只会被定义一次
  • 而useEffect的执行时机,是在 组件渲染后 ,由于只渲染一次,所以useEffect只执行一次,所以alert只弹出一次
  • 再看这段代码:

    import "./styles.css";
    import React from "react";
    export default function App() {
      const [count, setCount] = React.useState(0); // 加了这一行
      const value = { name: 1 };
      React.useEffect(() => {
        setCount(Math.random()); // 加了这一行
        ("render");
      }, [value]);
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
          <h2>Edit to see some magic happen!</h2>
    

    这段代码比上一段多了两句,我已经在注释中标出来了,请问现在 App渲染几次,value被定义几次, alert 会被弹出几次呢?

    答案是:无限循环,全都无限次

    这里循环的原因是:组件渲染 → useEffect执行 → setCount触发循环 → 组件渲染 → useEffect执行 → setCount触发循环...

    绝大多数的无限循环的情况,都是这段代码的缩影

    useCallback和useMemo

    针对上面的问题,React 官方提供的方法,就是使用 useMemo:

    import "./styles.css";
    import React from "react";
    export default function App() {
      const [count, setCount] = React.useState(0); 
      const value = React.useMemo(() => {
        return { name: 1 };
      }, []);
      React.useEffect(() => {
        setCount(Math.random()); 
        alert("render");
      }, [value]);
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
          <h2>Edit to see some magic happen!</h2>
    

    useMemo 的意思就是:不要每次渲染都重新定义,而是需要重新定义的时候再重新定义(第二个参数,依赖列表)。这里的依赖列表是空的,是因为useMemo里的回调函数确实没用到啥变量,如果有变量的话IDE也会提醒加上依赖。

    这就是使用useMemo的原理,useMemo适用于所有类型的值,加入这个值恰好是函数,那么用useCallback也可以。也就是说,useCallback是一种特殊的useMemo。

    如果定义了一个变量,满足下面的条件就最好用useMemo和useCallback给包裹住:

  • 它不是状态,也就是说,不是用useState定义的(redux中的状态实际上也是用useState定义的)
  • 它不是基本类型
  • 它会被放在useEffect的依赖列表里 || 自定义hook的返回值
  • 说一下第3条,中间的两个竖线是 或,也就是两者满足其一第3条就成立。自定义hook的返回值也成立是因为,你不知道自定义hook的返回值将会被用在哪里,它可能会被用在依赖也可能不会,所以干脆都加上;而像上面那个在组件中定义的value,你就可以见机行事了

    上面例子中的value变量就是一个经典的满足这三个条件的例子,只要遇到这个场景就使用useMemo和useCallback,就不会有无限循环的问题。

    当然,更简单粗暴的是,在**定义(不是使用!)**所有"非状态"的变量的时候都用useMemo和useCallback包裹中,也不会有无限循环的问题。但是没必要这么做,代码也不好看。