react-hook:useState与useEffect详解

背景

hook是什么呢?又改变了什么呢?我们先来看官网的原话:Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
为什么要使用hook呢?因为在react项目越来越大之后,我们会发现有时候一个class类往往很大,代码的复用性也很差,冗余的代码也很多,特别是在class类很多的时候,每个class类的生命周期的逻辑代码就很多了,维护起来更是麻烦。
跟着文章往下走,你就会知道hook使用的好处以及便捷,也能理解为什么react会推出hook这个功能。

useState

首先我们来看一个最基本的例子,点击按钮,改变count的值

import React, {
      Component } from 'react'
export default class App extends Component {
     
  constructor() {
     
    super()
    this.state = {
     
      count: 1
    }
  }
  handleChangeCount = () => {
     
    this.setState({
     
      count: 2
    })
  }
  render() {
     
    return (
      <div>
        <div>{
     this.state.count}</div> 
        <button onClick={
     this.handleChangeCount}>修改count的值</button>
      </div>
    )
  }
}

使用hook的useState写的话

import React, {
      useState } from 'react'
export default function App() {
     
  const [count, setCount] = useState(1)  // 1表示count的初始值,setCount是改变count的方法
  return (
    <div>
      <div>{
     count}</div>
      <button onClick={
     () => {
      setCount(2) }}>改变count的值</button>
    </div>
  )
}

我们会发现,代码量变成了原来的一半,而且看起来更好维护了。
我们来讲一讲useState,不使用useState的时候,我们会发现一个最麻烦的问题,就是要去维护this,因为我们知道,每一个class类的this,都是要从父组件继承的,本身是没有this的,所以需要使用constructor去初始化this。
而useState,让我们使用函数编程,我们之前写无状态组件的时候,用的就是函数编程,而使用useState之后,我们可以在函数编程里面使用状态。也就是说:count变成了函数里面的变量,setCount变成了函数里面的函数变量,那么使用的时候直接使用就行了,不再需要使用this
useState接收一个参数,返回的是一个数组,参数表示初始值,数组的第0项就是定义的变量,第1项就是改变变量的方法。
参数可以是基本数据类型,如string、number,也可以是复合数据类型,如array,object等,如下代码。

import React, {
      useState } from 'react'
export default function App() {
     
  const [count, setCount] = useState(0)
  const [obj, setObj] = useState({
     name: "aaa"})
  const [arr, setArr] = useState([1,2,3])

  return (
    <div>
      <div>{
     count}</div>
      <button onClick={
     () => {
      setCount(count + 1) }}>add</button>
      <div>{
     obj.name}---{
     obj.age}</div>
      <button onClick={
     () => {
      setObj({
     
        ...obj,
        age: 20,
        name: "bbb"
      }) }}>add</button>
      {
     
        arr.map(item => {
     
          return <div>{
     item}</div>
        })
      }
      <button onClick={
     () => {
      setArr([...arr, 4]) }}>add</button>
    </div>
  )
}

基本数据类型,可以直接修改,而复合数据类型,需要先通过解构运算符,然后再设置成新的复合数据类型。

useEffect

看完了useState,我们再来看看useEffect,首先一样来看下官网是怎么说的:Effect Hook 可以让你在函数组件中执行副作用操作
什么是副作用呢?官网也都举了例子,比如调用ajax获取数据,订阅监听,启动定时器等。
简单来说,useEffect就是来替代我们日常使用的生命周期函数componentDidUpdate和componentDidMount的。
也就是说,使用了useEffect之后,我们就不再需要写类似于componentDidMount之类的生命周期函数了,也不需要每一次都要关系组件的生命周期执行到哪了,什么时候需要执行的。来看个例子

import React, {
      Component } from 'react'
export default class App extends Component {
     
  constructor() {
     
    super()
    this.state = {
     
      count: 1
    }
  }
  handleChangeCount = () => {
     
    this.setState({
     
      count: 2
    })
  }
  componentDidMount = () => {
     
    document.title = this.state.count
  }
  componentDidUpdate = () => {
     
    document.title = this.state.count
  }
  render() {
     
    return (
      <div>
        <div>{
     this.state.count}</div> 
        <button onClick={
     this.handleChangeCount}>修改count的值</button>
      </div>
    )
  }
}

也就是,组件加载完成的时候,把title变成count的值,然后每次更新的时候,就更新title的count值。
再看看用useEffect写的

import React, {
      useEffect, useState } from 'react'
export default function App() {
     
  const [count, setCount] = useState(1)
  useEffect(() => {
     
      document.title = count
  })
  return (
    <div>
      <div>{
     count}</div>
      <button onClick={
     () => {
      setCount(2) }}>修改count的值</button>
    </div>
  )
}

可以看到,使用useEffect的代码,只有原来的一半,而且看起来也很舒服。
useEffect接收一个函数作为参数,会在页面加载完成的时候以及数据更新的时候,触发执行。
那么问题来了,如果我们只是想监听某些数据的更新,而不是全部数据的更新呢?useEffect还提供第二个参数,它是数组,数组的值表示想要监听变化的值,如

import React, {
      useEffect, useState } from 'react'
export default function App() {
     
  const [count, setCount] = useState(1)
  useEffect(() => {
     
      document.title = count
  },[])
  return (
    <div>
      <div>{
     count}</div>
      <button onClick={
     () => {
      setCount(2) }}>修改count的值</button>
    </div>
  )
}

此时我们传递了第二个参数为一个空数组,它表示不监听任何数值,那么useEffect就只会在页面加载完成的时候触发一次,而count更新的时候不会触发。如果想要count更新的时候触发,可以改成

import React, {
      useEffect, useState } from 'react'
export default function App() {
     
  const [count, setCount] = useState(1)
  useEffect(() => {
     
      document.title = count
  },[count])
  return (
    <div>
      <div>{
     count}</div>
      <button onClick={
     () => {
      setCount(2) }}>修改count的值</button>
    </div>
  )
}

我们再来想一个问题,我们都知道定时器在页面销毁的时候,需要清除,我们一般都会在componentUnMount,页面销毁的时候去把定时器清除,那么使用useEffect是如何清除呢?其实很简单,只需要在第一个参数的函数里面,return一个函数,函数里面写清除的方法就行了。来看代码

import React, {
      useEffect, useState } from 'react'
export default function App() {
     
  const [count, setCount] = useState(1)
  useEffect(() => {
     
    const timer = setInterval(() => {
     
      setCount(count + 1)
    }, 1000)
    return () => {
     
      clearInterval(timer)
    }
  })
  return (
    <div>
      <div>{
     count}</div>
    </div>
  )
}

这样在页面被卸载的时候,就会把定时器清除

你可能感兴趣的:(react)