zoukankan      html  css  js  c++  java
  • React函数式组件值之useEffect()

      Effect Hook 可以让你在函数组件中执行副作用操作,这里提到副作用,什么是副作用呢,就是除了状态相关的逻辑,比如网络请求,监听事件,查找 dom。

      可以这样说,在使用了useState或是useEffect这样的hooks之后,每次组件在render的时候都生成了一份本次render的state、function、effects,这些与之前或是之后的render里面的内容都是没有关系的。而对于class component来说,state是一种引用的形式。这就造成了二者在一些表现上的不同。

    一、基础用法

      定义一个函数和一个数组。函数体为组件初始化或变化时执行的代码,返回值为组件销毁前执行的代码。数组参数中放的是触发此函数的依赖项数据。

    1 useEffect(() => {
    2   // 相当于 componentDidMount、componentDidUpdate
    3   console.log("code");
    4   return () => {
    5     // 相当于 componentWillUnmount
    6     console.log("code");
    7   }
    8 }, [/*依赖项*/])

    二、监听参数

      类组件在绑定事件、解绑事件、设定定时器、查找 dom 的时候,是通过 componentDidMount、componentDidUpdate、componentWillUnmount 生命周期来实现的,而 useEffect 会在组件每次 render 之后调用,就相当于这三个生命周期函数,只不过可以通过传参来决定是否调用。

      其中注意的是,useEffect 会返回一个回调函数,作用于清除上一次副作用遗留下来的状态,如果该 useEffect 只调用一次,该回调函数相当于 componentWillUnmount 生命周期。

    决定useEffect中各部分代码角色的是第二个参数:

    • 什么都不传,组件每次 render 之后 useEffect 都会调用,相当于 componentDidMount 和 componentDidUpdate
    • 传入一个空数组 [], 只会调用一次,相当于 componentDidMount 和 componentWillUnmount
    • 传入一个数组,其中包括变量,只有这些变量变动时,useEffect 才会执行
     1 function App () {
     2   const [ count, setCount ] = useState(0)
     3   const [ width, setWidth ] = useState(document.body.clientWidth)
     4   const onChange = () => {
     5     setWidth(document.body.clientWidth)
     6   }
     7   //最简单用法
     8   useEffect(() => {
     9     //只有方法体,相当于componentDidMount和componentDidUpdate中的代码
    10     document.title = count;
    11   })
    12   //加返回值用法
    13   useEffect(() => {
    14     //添加监听事件,相当于componentDidMount和componentDidUpdate中的代码
    15     window.addEventListener('resize', onChange, false);
    16     //返回的函数用于解绑事件,相当于componentWillUnmount中的代码
    17     return () => {
    18       window.removeEventListener('resize', onChange, false)
    19     }
    20   })
    21   //加空数组参数用法
    22   useEffect(() => {
    23     // 相当于 componentDidMount
    24     window.addEventListener('resize', onChange, false)
    25     return () => {
    26       // 相当于 componentWillUnmount
    27       window.removeEventListener('resize', onChange, false)
    28     }
    29   }, []);
    30   //加监听值用法
    31   useEffect(() => {
    32     //只有当count的值发生变化,此函数才会执行
    33     console.log(`count change: count is ${count}`)
    34   }, [ count ]);
    35   return (
    36     <div>
    37       页面名称: { count } 
    38       页面宽度: { width }
    39       <button onClick={() => { setCount(count + 1)}}>点我</button>
    40     </div>
    41     )
    42 }

      其实Function Component 不存在生命周期,把 Class Component 的生命周期概念搬过来试图对号入座只是一种辅助记忆手段,Function Component 仅描述 UI 状态,React 会将其同步到 DOM,仅此而已。

    三、使用优化

      我们在使用useState的时候,经常碰到capture value的问题,比如下面代码会输出5而不是3:

     1 const App = () => {
     2   const [temp, setTemp] = React.useState(5);
     3   const printTime = () => {
     4     setTimeout(() => console.log(temp), 3000);
     5   };
     6   return (
     7     <div onClick={() => {
     8         printTime();
     9         setTemp(3);
    10       }}
    11     >clickMe</div>
    12   );
    13 };

      在printTime函数执行的那个 Render 过程里,temp 的值可以看作常量 5,执行 setTemp(3) 时会交由一个全新的 Render 渲染,所以不会执行printTime函数。而 3 秒后执行的内容是由 temp 为 5 的那个 Render 发出的,所以结果自然为 5。

      原因就是 temp、printTime 都拥有 Capture Value 特性。而useEffect 也一样具有 Capture Value 的特性。

      利用 useRef 就可以绕过 Capture Value 的特性。可以认为 ref 在所有 Render 过程中保持着唯一引用,因此所有对 ref 的赋值或取值,拿到的都只有一个最终状态,而不会在每个 Render 间存在隔离。也可以简洁的认为,ref 是 Mutable 的,而 state 是 Immutable 的。

     1 function Example() {
     2   const [count, setCount] = useState(0);
     3   const latestCount = useRef(count);
     4   useEffect(() => {
     5     //设置最新变量的引用
     6     latestCount.current = count;
     7     setTimeout(() => {
     8       //读取引用指向的最新值
     9       console.log(`You clicked ${latestCount.current} times`);
    10     }, 3000);
    11   });
    12   return (
    13     <div>
    14       <p>You clicked {count} times</p>
    15       <button onClick={() => setCount(count + 1)}>Click me</button>
    16     </div>
    17   );
    18 }
  • 相关阅读:
    面向对象的JavaScript-009-闭包
    面向对象的JavaScript-007-Function.prototype.bind() 的4种作用
    面向对象的JavaScript-006-Function.prototype.apply()的3种作用
    面向对象的JavaScript-005-Function.prototype.call()的3种作用
    面向对象的JavaScript-004
    面向对象的JavaScript-003
    面向对象的JavaScript-002
    面向对象的JavaScript-001
    IOC容器特性注入第一篇:程序集反射查找
    AWS EC2 在WINDOWS平台使用FSX
  • 原文地址:https://www.cnblogs.com/guanghe/p/14178482.html
Copyright © 2011-2022 走看看