React-Native 加入小组

22个成员 4个话题 创建时间:2020-02-06

React 高级 HOOKS : useEffect()

发表于2020-02-18 1063次查看

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

 

/**

 * 

 *   useState():在函数中提供state数据

 * 

 *   useEffect(): 

 *   The Effect Hook lets you perform side effects in function components:

 *   side effects :副作用  容易造成副作用的污染*作:网络请求,事件监听 dom*作

 * 

 *  class 组件: 有生命周期函数钩子  方便处理 副作用*作

 *  

 *  class 组件 

 *   01 生命周期臃肿

 *   02 逻辑复用

 *       继承:不支持的多继承 

 *       渲染:组件嵌套 性能差

 *   03  this 指向

 *    

 */

 

//  01 需求:组件在状态更新的时候 改变 document.title

 

// class App extends React.Component{

//   constructor(props){

//     super(props)

//     this.state={

//        count:0

//     }

//   }

 

//   // 1.2 we typically want to perform our effects after React has updated the DOM.

//   // This is why in React classes, we put side effects into componentDidMount and componentDidUpdate.

//   componentDidMount(){

//     console.log('componentDidMount');

//     document.title= `You clicked ${this.state.count} times`

//   }

 

//   componentDidUpdate(){

//     console.log('componentDidUpdate');

//     document.title= `You clicked ${this.state.count} times`

//   }

 

//   //  1.1 In React class components, the render method itself shouldn’t cause side effects.

//   //  It would be too early

//   render(){

//       return (

//           <div>

//             <p>You Clicked {this.state.count} times</p>

//             <button onClick={()=>this.setState({count:this.state.count+1})} >Click me</button>

//           </div>

//         )

//   }

 

// }

 

// 1.3 useEffect() 解决需求

//代码复制: we have to duplicate(不得不复制) the code between these two lifecycle methods in class.

// This is because in many cases we want to perform the same side effect regardless of whether the component just mounted, or if it has been updated.

 

// 没有render after方法:  we want it to happen after every render — but React class components don’t have a method like this. 

// 抽离代码 也需要复制:We could extract a separate method but we would still have to call it in two places.

// Now let’s see how we can do the same with the useEffect Hook.

 

// 02 useEffect()  每次render之后 直接使用副作用*作

 

// function App(props){

//   const [count,setCount] = useState(0)

  

//   // 2.1 使用

//   useEffect(()=>{

//     document.title=`you click ${count} times`

//   })


 

//   return (

//     <div>

//       <p>You Clicked {count} times</p>

//       <button onClick={()=>setCount(count+1)} >Click me</button>

//     </div>

//   )

// }

 

// 2.1 使用理解

// Tip:If you’re familiar with React class lifecycle methods, 

// you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined

 

// 2.2 useEffect 做了什么

// render 后做点事情(副作用函数); 传递函数;

// 调用函数 :call it later after performing the DOM updates

// 其他事情:ocument title, but we could also perform data fetching or call some other imperative API.

 

// 2.3 useEffect 为什么在组件中使用

// 能够有效的访问state变量或者props:Placing useEffect inside the component lets us access the count state variable (or any props) right from the effect.

// 函数作用域的支持: We don’t need a special API to read it — it’s already in the function scope

 

// 2.4 Does useEffect run after every render? 

// 默认是的: it runs both after the first render and after every update

//  “mounting” and “updating” =>“after render”

 

// 3.0 释放资源、回收机制

// 一般情况:cleanup

// 特殊情况:订阅额外资源

// 危险 内存泄漏 memory leak 

// class App extends React.Component{

//   constructor(props){

//     super(props)

//     this.state={

//        count:0,

//        width:document.body.clientWidth

//     }

//   }

 

//   resizeWidth=()=>{

//     this.setState({

//       width:document.body.clientWidth

//     }

//     )

//   }

 

//   componentDidMount(){

//     document.title= `You clicked ${this.state.count} times`

//     window.addEventListener('resize',this.resizeWidth,false)

//   }

 

//   componentDidUpdate(){

//     document.title= `You clicked ${this.state.count} times`

//   }

 

//   componentWillUnmount(){

//     window.removeEventListener('resize',this.resizeWidth,false)

//   }

 

//   render(){

//       return (

//           <div>

//             <p>You Clicked {this.state.count} times</p>

//             <p>body client width {this.state.width} </p>

//             <button onClick={()=>this.setState({count:this.state.count+1})} >Click me</button>

//           </div>

//         )

//   }

 

// }

 

// 04 useEffect() 返回函数

// function App(props){

//     const [count,setCount] = useState(0)

//     const [width,setWidth] = useState(document.body.clientWidth)

    

//     const resizeWidth=()=>{

//       setWidth(document.body.clientWidth)

//     }

      

 

//     // 设计 绑定资源和释放资源在一起使用 通过return函数

//     // 符合 after render ,每次render 之后都会调用

//     // 问题 : 每次render 之后 不应该都进行一次绑定和解绑

//     //       useEffect() 需要 componentDidMount(),componentWillUnmount()进行*作

//     useEffect(()=>{

//       window.addEventListener('resize',resizeWidth,false)

//       console.log('addEventListener');

//       return ()=>{

//         console.log('removeEventListener');

//         window.removeEventListener('resize',resizeWidth,false)

//       }

//     })

 

//     // 每次render之后 就会调用

//     //相当于  componentDidMount, componentDidUpdate

//     useEffect(()=>{

//       document.title=`you click ${count} times`

//     })

  

  

//     return (

//       <div>

//         <p>You Clicked {count} times</p>

//         <p>body client width {width} </p>

//         <button onClick={()=>setCount(count+1)} >Click me</button>

//       </div>

//     )

//   }


 

  // useEffect() 参数解决:第二个参数

  function App(props){

    const [count,setCount] = useState(0)

    const [width,setWidth] = useState(document.body.clientWidth)

    

    const resizeWidth=()=>{

      setWidth(document.body.clientWidth)

    }

      

 

    // 问题 : 每次render 之后 不应该都进行一次绑定和解绑

    //       useEffect() 需要 componentDidMount(),componentWillUnmount()进行*作

    // 解决 :第二个参数 传入一个空数组[],只会调用一次componentDidMount(),componentWillUnmount()

    useEffect(()=>{

      window.addEventListener('resize',resizeWidth,false)

      console.log('addEventListener');

      return ()=>{

        console.log('removeEventListener');

        window.removeEventListener('resize',resizeWidth,false)

      }

    },[])

 

    // 第二个参数什么都不传:每次render之后 都会调用

    //相当于  componentDidMount, componentDidUpdate

    // useEffect(()=>{

    //   console.log('重新设置标题:count 点击了或者重新改变尺寸了');

    //   document.title=`you click ${count} times`

    // })

 

    // 只有点击时候 count 改变 的时候 才设置标题;尺寸改变 不影响 设置标题

    // 解决 :第二个参数 传入一个空数组[变量]  只有变量变化了 才能触发 副作用*作执行

    useEffect(()=>{

      console.log('重新设置标题:第一次mouned 或则 count 点击');

      document.title=`you click ${count} times`

    },[count])

  

  

    return (

      <div>

        <p>You Clicked {count} times</p>

        <p>body client width {width} </p>

        <button onClick={()=>setCount(count+1)} >Click me</button>

      </div>

    )

  }








 

export default App;


 

发表回复
你还没有登录,请先 登录或 注册!
话题作者
Web全栈讲师 / 鸿蒙高级讲师