React Hooks生命周期钩子

React Hooks介绍

  • 对函数型组件进⾏增强, 让函数型组件可以存储状态, 可以拥有处理副作⽤的能⼒.
  • 让开发者在不使⽤类组件的情况下, 实现相同的功能.

Hooks 要解决的问题
1、缺少逻辑复⽤机制。为了复⽤逻辑增加⽆实际渲染效果的组件,增加了组件层级 显示⼗分臃肿,增加了调试的难度以及运⾏效率的降低
2、类组件经常会变得很复杂难以维护。将⼀组相⼲的业务逻辑拆分到了多个⽣命周期函数中在⼀个⽣命周期函数内存在多个不相⼲的业务逻辑
3、类成员⽅法不能保证this指向的正确性

React Hooks 使⽤
Hooks 意为钩⼦, React Hooks 就是⼀堆钩⼦函数, React 通过这些钩⼦函数对函数型组件进⾏增强, 不同的钩⼦函数提供了不同的功能

useState():这个钩子的功能是可以让函数型组件可以保存状态,在现有的认知中,函数中的变量在执行完就会背释放掉,所以函数型组件原本是不可以保存数据的。useState这个钩子的内部使用闭包来实现保存数据的

import React, { useState } from "react";

function App(props) {
  const [count, setCount] = useState(() => {
    return props.count || 0
  })
  const [person, setPerson] = useState({name: '张三', age: 20})

  function handCound () {
    setCount(count => {
      return count + 2
    })
  }
  return (
    <div className="App">
     <div>{count}</div>
     <div>{person.name}-{person.age}</div>
      <button onClick={handCound}>+1</button>
      <button onClick={() => setPerson({name: '李四', age: 30})}>修改</button>
    </div>
  );
}

export default App;

1、接收唯⼀的参数即状态初始值. 初始值可以是任意数据类型.
2、 返回值为数组. 数组中存储状态值和更改状态值的⽅法. ⽅法名称约定以set开头, 后⾯加上状态名称
3、⽅法可以被调⽤多次. ⽤以保存不同状态值.
4、参数可以是⼀个函数, 函数返回什么, 初始状态就是什么, 函数只会被调⽤⼀次, ⽤在初始值是动态值的情况.
5、设置状态值⽅法的参数可以是⼀个值也可以是⼀个函数
6、设置状态值⽅法的⽅法本身是异步的

useReducer() 这个钩子的功能是让函数型组件保存状态,使用方式与Redux类似,useReducer的第一个参数是一个reducer函数,第二个参数是默认值,返回值是一个数组,第一个值为需要处理的状态,第二个值是dispatch函数,通过dispatch方法可以触发action执行reducer函数

import React, { useReducer } from "react";

function reducer (state, action) {
 switch (action.type) {
   case 'increment':
     return state + 1
 }
}
function App(props) {
 const [count, dispatch] = useReducer(reducer, 0)
 return (
   <div className="App">
    <div>{count}</div>
    <button onClick={() => dispatch({type: 'increment'})}>+1</button>
   </div>
 );
}

export default App;

useContext() 这个钩子的用途是跨组件传值,简化数据获取时的代码

// 不使用useContext
import React, { createContext } from "react";
const countContext = createContext()

function App(props) {
  return (
    <countContext.Provider value={100}>
      <Foo></Foo>
    </countContext.Provider>
  );
}

function Foo () {
  return (
    <countContext.Consumer>
      {
        value => {
          return <div>{value}</div>
        }
      }
    </countContext.Consumer>
  )
}

export default App;
// 使用useContext 
import React, { createContext, useContext } from "react";

const countContext = createContext()

function App(props) {
  return (
    <countContext.Provider value={110}>
      <Foo></Foo>
    </countContext.Provider>
  );
}

function Foo () {
  const value = useContext(countContext)
  return <div>{value}</div>
}

export default App;

useEffect() 让函数型组件拥有处理副作⽤的能⼒. 类似⽣命周期函数
可以把 useEffect 看做 componentDidMount, componentDidUpdate 和 componentWillUnmount 这三个函数的组合.
使用方法:
useEffect(() => {})
组件渲染完成、状态修改时执行

function App(props) {
  const [count, setCount] = useState(0)
  const [person, setPerson] = useState({name: '张三'})
  
  useEffect(() => {
    console.log('1111')
    document.title = count
  })
  return (
    <div>
      <span>{count}</span>
      <span>{person.name}</span>
      <button onClick={() => setCount(count + 1)}>添加</button>
      <button onClick={() => setPerson({name: '李四'})}>修改</button>
    </div>
  );
}

export default App;

useEffect(() => {}, [])
第二个参数为空数组,该钩子 在DOM渲染完成执行一次,当第二个参数指定了某个属性时,当该属性改变时,会再次触发这个钩子

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


function App(props) {
  const [count, setCount] = useState(0)
  const [person, setPerson] = useState({name: '张三'})

  // 第二个参数为空数组,该钩子 在DOM渲染完成执行一次,当第二个参数指定了某个属性时,当该属性改变时,会触发更新
  // useEffect(() => {
  //   console.log('1111')
  //   document.title = count
  // }, [])

  useEffect(() => {
    console.log('1111')
    document.title = count
  }, [count])
  return (
    <div>
      <span>{count}</span>
      <span>{person.name}</span>
      <button onClick={() => setCount(count + 1)}>添加</button>
      <button onClick={() => setPerson({name: '李四'})}>修改</button>
    </div>
  );
}

export default App;

useEffect(() => () => {}) ,组件卸载前执行

useEffect 解决的问题:
1、 按照⽤途将代码进⾏分类 (将⼀组相⼲的业务逻辑归置到了同⼀个副作⽤函数中)
2、简化重复代码, 使组件内部代码更加清晰

useEffect中使用异步函数
useEffect中的参数函数不能是异步函数, 因为useEffect函数要返回清理资源的函数, 如果是异步函数就变成了返回Promise

 // 异步函数执行
  useEffect(() => {
    (async function () {
      let res = await axios.get()
    })()
  }, [])

useMemo()
useMemo 的⾏为类似Vue中的计算属性, 可以监测某个值的变化, 根据变化值计算新值
useMemo 会缓存计算结果. 如果监测值没有发⽣变化, 即使组件重新渲染, 也不会重新计算. 此⾏为可以有助于避免在每个渲染上进⾏昂贵的计算
调用useMemo钩子函数传递两个参数,第一个参数是回调函数,用来计算新值,第二个参数为需要检测的值,当检测的值发生变化,这个钩子函数就会被执行,useMemo 函数的返回值就是计算后的新值

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


function App(props) {
  const [count, setCount] = useState(0)
  const [bool, setBool] = useState(true)

  const result = useMemo(() => {
    // 点击修改按钮,触发组件重新渲染,但是count值未发生改变,不会触发useMemo钩子
    console.log('111')
    return count * 2
  }, [count])
  return (
    <div>
      <span>{count}---{result}</span>
      <span>{bool ? '真': '假'}</span>
      <button onClick={() => setCount(count + 1)}>添加</button>
      <button onClick={() => setBool(!bool)}>修改</button>
    </div>
  );
}

export default App;

memo ⽅法
性能优化, 如果本组件中的数据没有发⽣变化, 阻⽌组件更新. 类似类组件中的 PureComponent 和 shouldComponentUpdate

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

function App(props) {
  const [count, setCount] = useState(0)
  return (
    <div>
      <span>{count}</span>
      <button onClick={() => setCount(count + 1)}>添加</button>
      <Foo/>
    </div>
  );
}

// memo 方法接收一个组件作为参数,并返回一个新的组件,
// 判断这个组件中数据是否发生变化,如果数据没发生变化,则阻止更新
const Foo = memo(function Foo() {
  console.log('Foo重新渲染')
  return <div>我 是Foo</div>
})

export default App;

useCallback()
性能优化, 缓存函数, 使组件重新渲染时得到相同的函数实例.

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

function App(props) {
  const [count, setCount] = useState(0)
  // 将计数器属性重置
  const resetCount = () => {
    setCount(0)
  }
  return (
    <div>
      <span>{count}</span>
      <button onClick={() => setCount(count + 1)}>添加</button>
      {/* 将resetCount方法传给子组件 */}
      <Foo resetCount={resetCount}/>
    </div>
  );
}

// memo 方法接收一个组件作为参数,并返回一个新的组件,
// 判断这个组件中数据是否发生变化,如果数据没发生变化,则阻止更新
const Foo = memo(function Foo(props) {
  console.log('Foo重新渲染')
  return <div>
    我 是Foo
    <button onClick={props.resetCount}>重置</button>
  </div>
})
// 点击重置按钮,若count值发生修改,则触发组件重新渲染
// 生成新的resetCount实例,子组件检测到实例发生变化,更新子组件
export default App;

点击重置按钮,若count值发生修改,则触发组件重新渲染,生成新的resetCount实例,子组件检测到实例发生变化,更新子组件,而实际上子组件的值并未发生变化,使用useCallback可解决这个问题

import React, { useState, memo, useCallback } from "react";

function App(props) {
  const [count, setCount] = useState(0)
  // 将计数器属性重置
  // const resetCount = () => {
  //   setCount(0)
  // }
  const resetCount = useCallback(() => setCount(0), [setCount])
  return (
    <div>
      <span>{count}</span>
      <button onClick={() => setCount(count + 1)}>添加</button>
      {/* 将resetCount方法传给子组件 */}
      <Foo resetCount={resetCount}/>
    </div>
  );
}

// memo 方法接收一个组件作为参数,并返回一个新的组件,
// 判断这个组件中数据是否发生变化,如果数据没发生变化,则阻止更新
const Foo = memo(function Foo(props) {
  console.log('Foo重新渲染')
  return <div>
    我 是Foo
    <button onClick={props.resetCount}>重置</button>
  </div>
})

export default App;

useRef()
1、获取DOM元素对象
2、 保存数据 (跨组件周期),即使组件重新渲染, 保存的数据仍然还在. 保存的数据被更改不会触发组件重新渲染.

import React, { useRef } from "react";
function App(props) {
  const D = useRef()
  return (
    <div ref={D}>
      <span>kajsdh</span>
      <button onClick={() => console.log(D)}>获取DOM</button>
    </div>
  );
}
// 最终得到一个current对象:{current: div}  
export default App;

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

function App(props) {
  const [count, setCount] = useState(0)
  // 保存数据 (跨组件周期),即使组件重新渲染, 保存的数据仍然还在. 保存的数据被更改不会触发组件重新渲染.
  let timer = useRef()

  useEffect(() => {
    timer.current = setInterval(() => {
      setCount(count => count + 1)
    }, 1000);
  }, [])

  const stopInter = () => {
    clearInterval(timer.current)
  }
  return (
    <div>
      <span>{count}</span>
      <button onClick={stopInter}>停止定时器</button>
    </div>
  );
}
export default App;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值