Introduction to react's Hooks, use of useState and useEffect side effects

1. Basic introduction to Hooks

  • Hooks 是 React v16.8 中的新增功能
  • 为函数组件提供状态、生命周期等原本 class 组件中提供的 React 功能
  • 可以理解为通过 Hooks 为函数组件钩入 class 组件的特性
  • 注意:Hooks 只能在函数组件中使用,自此,函数组件成为 React 的新宠儿
  • 可以在项目中同时使用hooks和class

2. Use of useState

2.1 Simple to use

  • 一个 Hook 就是一个特殊的函数,让你在函数组件中获取状态等 React 特性
  • useState使用场景:当你想要在函数组件中,使用组件状态时,就要使用 useState Hook 了
  • useState作用:为函数组件提供状态(state)
import {
    
     useState } from 'react'

const Count = () => {
    
      
  // stateArray 是一个数组
  const stateArray = useState(0)

  const state = stateArray[0]
  const setState = stateArray[1]

  return (
    <div>
      {
    
    /* 展示状态值 */}
      <h1>状态为:{
    
    state}</h1>
      {
    
    /* 点击按钮,让状态值 +1 */}
      <button onClick={
    
    () => setState(state + 1)}>+1</button>
    </div>
  )
}

2.2 Simplification of array structure

import {
    
     useState } from 'react'

const Count = () => {
    
    
  // 解构:
  const [count, setCount] = useState(0)

  return (
    <div>
      <h1>计数器:{
    
    state}</h1>
      <button onClick={
    
    () => setState(state + 1)}>+1</button>
    </div>
  )
}

2.3 Reading and modifying status

  • 读取状态:useState 提供的状态,是函数内部的局部变量,可以在函数内的任意位置使用
const Counter = () => {
    
    
  const [user, setUser] = useState({
    
     name: 'jack', age: 18 })
  
  return (
  	<div>
    	<p>姓名:{
    
    user.name}</p>
			<p>年龄:{
    
    user.age}</p>
    </div>
  )
}

Modify status:

  • setCount(newValue) 是一个函数,参数表示:新的状态值
    • 调用该函数后,将使用新的状态值替换旧值
    • 修改状态后,因为状态发生了改变,所以,该组件会重新渲染
const Counter = () => {
    
    
  const [user, setUser] = useState({
    
     name: 'jack', age: 18 })
  
  const onAgeAdd = () => {
    
    
    setUser({
    
    
      ...user,
      age: user.age + 1
    })
  }
  
  return (
  	<div>
    	<p>姓名:{
    
    user.name}</p>
			<p>年龄:{
    
    user.age}</p>
     	<button onClick={
    
    onAgeAdd}>年龄+1</button>
    </div>
  )
}
  • When modifying the status, be sure to replace the old status with the new status

2.3 Component update process

The execution process of function components after using useState hook, and the changes in state values:

  • 组件第一次渲染:
    • 1.从头开始执行该组件中的代码逻辑
    • 2.调用 useState(0) 将传入的参数作为状态初始值,即:0
    • 3.渲染组件,此时,获取到的状态 count 值为: 0
  • 组件第二次渲染:
    • 1.点击按钮,调用 setCount(count + 1) 修改状态,因为状态发生改变,所以,该组件会重新渲染
    • 2.组件重新渲染时,会再次执行该组件中的代码逻辑
    • 3.再次调用 useState(0),此时 React 内部会拿到最新的状态值而非初始值,比如,该案例中最新的状态值为 1
    • 4.再次渲染组件,此时,获取到的状态 count 值为:1
  • The initial value (parameter) of useState will only take effect when the component is rendered for the first time.

core code

import {
    
     useState } from 'react'

const Count = () => {
    
    
  const [count, setCount] = useState(0)

  return (
    <div>
      <h1>计数器:{
    
    count}</h1>
      <button onClick={
    
    () => setCount(count + 1)}>+1</button>
    </div>
  )
}

3. Use of useEffect

3.1 Introduction to side effects

content:

  • Usage scenario: When you want to handle side effects in a function component , you need to use useEffect Hook

  • Role: Handle side effects in function components

  • Question: What are the side effects?

  • Answer: In computer science, a function or other operation is said to have a side effect if it modifies the value of a state variable outside its local environment. By analogy,
    for 999 cold medicine:

  • (Main) Function: Used for headaches, fever, nasal congestion, runny nose, sore throat, etc. caused by colds

  • Side effects: Drowsiness, drowsiness, thirst, and weakness may be seen

  • Understanding: Side effects are relative to the main effect. In addition to the main effect of a function (for example, a function), other effects are side effects.

  • For React components, the main function is to render UI based on data (state/props) , other than that are side effects (for example, manually modifying the DOM)

  • Common side effects: data (Ajax) requests, manual modification of DOM, localStorage, console.log operations, etc.

Summary :

For react components, operations other than rendering UI can be called side effects.

let a = 1

const Count = () => {
    
    
  const [count, setCount] = useState(0)

  const handleClick = () => {
    
    
    setCount(count + 1)
  }
  
  console.log('aaa')
  axios.post('http://xxx')
  localStorage.setItem()
  a = 2
  
  return (
    <div>
      <h1>计数器:{
    
    count}</h1>
      <button onClick={
    
    handleClick}>+1</button>
    </div>
  )
}

3.2 Basic use

  • Usage scenario: Use useEffect Hook when you want to handle side effects in a function component.

  • Function: Handle some side effects in function components

  • Note: In actual development, side effects are inevitable. Therefore, react specifically provides useEffect Hook to handle side effects in function components.

grammar:

  • Parameters: callback function (called effect ), which is to write side effect code in this function
  • Execution timing: This effect will be executed after the component is rendered for the first time and after each component update.
  • Equivalent to componentDidMount + componentDidUpdate

core code

import {
    
     useEffect } from 'react'

const Counter = () => {
    
    
  const [count, setCount] = useState(0)
  
  useEffect(() => {
    
    
    document.title = `当前已点击 ${
      
      count}`
  })
  
  return (
  	<div>
    	<h1>计数器:{
    
    count}</h1>
      <button onClick={
    
    () => setCount(count + 1)}>+1</button>
    </div>
  )
}

3.3 Dependencies

content:

  • Problem: If there is another state in the component, when the other state is updated, the effect callback just now will also be executed.

  • Default: The effect callback of useEffect will be executed as long as the status is updated.

  • Performance optimization: skip unnecessary execution and only execute the corresponding effect when the count changes.

  • grammar:

    • Second parameter: optional, you can also pass an array, the elements in the array can become dependencies (deps)
    • This example indicates that the effect will be re-executed only when count changes.

    core code

import {
    
     useEffect } from 'react'

const Counter = () => {
    
    
  const [count, setCount] = useState(0)
  const [loading, setLoading] = useState(false)
  
  useEffect(() => {
    
    
    document.title = `当前已点击 ${
      
      count}`
  }, [count])
  
  return (
  	<div>
    	<h1>计数器:{
    
    count}</h1>
      <button onClick={
    
    () => setCount(count + 1)}>+1</button>
      <button onClick={
    
    () => setLoading(!loading)}>切换 loading</button>
    </div>
  )
}

3.4 Don’t lie about dependencies

content:

  • The data (for example, count) used in the useEffect callback function (effect) is the dependency data and should appear in the dependency array.
  • If a certain data is used in the useEffect callback function, but does not appear in the dependencies array, some bugs will occur!
  • So, don’t lie about useEffect dependency
const App = () => {
    
    
  const [count, setCount] = useState(0)
  
  // 错误演示:
  useEffect(() => {
    
    
    document.title = '点击了' + count + '次'
  }, [])
  
  return (
    <div>
      <h1>计数器:{
    
    count}</h1>
      <button onClick={
    
    () => setCount(count + 1)}>+1</button>
    </div>
  )
}

useEffect complete guide: https://overreacted.io/zh-hans/a-complete-guide-to-useeffect/

3.5 Dependencies can be empty arrays

Content :

  • The second parameter of useEffect can also be an empty array ([]) , which means that the effect will only be executed after the component is rendered for the first time.

  • Usage scenarios: 1. Event binding 2. Sending requests to obtain data, etc.

  • grammar:

    • This effect will only be executed after the component is rendered for the first time. Therefore, operations such as event binding that only need to be executed once can be performed.
    • At this time, it is equivalent to the role of the componentDidMount hook function of the class component.
useEffect(() => {
    
    
  const handleResize = () => {
    
    }
  window.addEventListener('resize', handleResize)
}, [])

Notice:

  • Like useState Hook, useEffect Hook can also be called multiple times in a component.
  • Recommendation: One useEffect only handles one function. When there are multiple functions, use multiple useEffects.

3.6 Cleanup work

content:

  • The return value of effect is optional and can be omitted. You can also return a cleanup function to perform cleanup operations such as event unbinding.
  • Execution timing of the cleanup function:
    • The cleanup function will be executed when the component is unloaded and the next time the side effect callback function is called, to clear the last side effect.
    • If the dependencies are an empty array, they will be executed when the component is unloaded. Equivalent to componentscomponetWillUnmount

Core code:

useEffect(() => {
    
    
  const handleResize = () => {
    
    }
  window.addEventListener('resize', handleResize)
  
  // 这个返回的函数,会在该组件卸载时来执行
  // 因此,可以去执行一些清理操作,比如,解绑 window 的事件、清理定时器 等
  return () => window.removeEventListener('resize', handleResize)
}, [])

3.7 4 ways to use useEffect

// 1
// 触发时机:1 第一次渲染会执行 2 每次组件重新渲染都会再次执行
// componentDidMount + ComponentDidUpdate
useEffect(() => {
    
    })

// 2(使用频率最高)
// 触发时机:只在组件第一次渲染时执行
// componentDidMount
useEffect(() => {
    
    }, [])

// 3(使用频率最高)
// 触发时机:1 第一次渲染会执行 2 当 count 变化时会再次执行
// componentDidMount + componentDidUpdate(判断 count 有没有改变)
useEffect(() => {
    
    }, [count])

// 4
useEffect(() => {
    
    
  // 返回值函数的执行时机:组件卸载时
  // 在返回的函数中,清理工作
  return () => {
    
    
  	// 相当于 componentWillUnmount
  }
}, [])

useEffect(() => {
    
    
  
  // 返回值函数的执行时机:1 组件卸载时 2 count 变化时
  // 在返回的函数中,清理工作
  return () => {
    
    }
}, [count])

3.8 Send a request

content:

  • In the component, you can use useEffect Hook to send a request (side effect) to obtain data

  • Note: effect can only be a synchronous function, async cannot be used

    • Because if the effect is async, the return value is a Promise object. In this case, there is no guarantee that the cleanup function will be called immediately
  • In order to use async/await syntax, you can create an async function inside the effect and call

Core code:

// 错误演示:不要给 effect 添加 async
useEffect(async () => {
    
    
  const res = await axios.get('http://xxx')
  return () => {
    
    }
}, [])

// 正确使用
useEffect(() => {
    
    
  const loadData = async () => {
    
    
    const res = await axios.get('http://xxx')
  }
  loadData()
  
  return () => {
    
    }
}, [])

3.9 axios requests local json data

  • 需求:发起axios请求本地某json数据
  • 第一步:需要将json文件放在 public 目录下 !!!
  • 第二步:引入axios import axios from 'axios'
  • 第三步:发起请求
import React, {
    
     useEffect, useState } from 'react'
import axios from 'axios'
export default function App() {
    
    
  const [list, setList] = useState([])
  useEffect(() => {
    
    
//接口地址可省略 public    
axios.get('http://localhost:3000/data.json').then((res) => {
    
    
      console.log('打印res', res.data)
      setList(res.data.list)
    })
  }, [])
  return (
    <ul>
      {
    
    list.map((item) => (
        <li key={
    
    item.id}>{
    
    item.comment}</li>
      ))}
    </ul>
  )
}

Guess you like

Origin blog.csdn.net/Gik99/article/details/132259286