React学习之hooks

85 阅读4分钟

1、useState

import { useState } from 'react'

function Home() {
  const [count, setCount] = useState(0)
  return (
    <div>
      <button onClick={() => {setCount(count + 1)}}>{count}</button>
    </div>
  )
}

export default Home

状态的读取和修改:

  1. useState传过来的参数,作为count的初始值
  2. [count, setCount]这里的写法是一个解构赋值,useState返回值是一个数组,名字可以自定义,但是顺序不能换
  3. setCount函数用来修改count值,不能直接修改原值,而且生成一个新值来替换旧值:setCount(基于原值计算得到的新值)
  4. count和setCount是一对,是绑在一起的,setCount只能用来修改对应的count值

组件更新:

useState初始值只在首次渲染生效,后续只要调用setCount整个组件中代码都会重新执行,此时的count每次拿到的都是最新值。

  • 首次渲染:组件内部的代码会被执行一次,其中useState也会跟着执行,初始值只在首次渲染时生效

  • 更新渲染:组件会再次渲染,函数会被再次执行,useState再次执行,得到的新的count值不是0而是修改之后的1,模板会用新值渲染

2、useState的回调函数

使用场景:参数只会再组件的初始渲染中起作用,后续渲染会被忽略,如果初始state需要通过计算才能获得,则可以传入一个函数,在函数中计算并返回初始的state,此函数只在初始渲染时被调用

import { useState } from 'react'

function Counter(props) {
  const [count, setCount] = useState(() => {
    return props.count
  })

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

function Home() {
  return <Counter count={20}></Counter>
}

export default Home

useState注意重点

  1. useState的初始参数只会在组件首次渲染时使用,再次更新时会被忽略
  2. 每次通过setCount修改状态都会引起组件重新渲染
  3. useState不可以在除了函数组件之外的地方,比如分支语句,循环语句,内部函数中执行
  4. 如果初始值需要计算才能得到可以使用回调函数的写法来确定useState的初始值

3、useEffect

  1. 默认状态(无依赖项):组件初始化的时候先执行一次,等到每次数据修改组件更新再次执行(首次执行+每次组件更新执行)
  2. 添加一个空数组依赖项:组件只在初始化的时候执行一次(首次执行)
  3. 依赖特定项:组件初始化的时候执行一次,依赖的特定项发生变化会再次执行(首次执行+依赖项变化执行)
import { useState, useEffect } from 'react'

function Home() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    console.log('每次数据更新时都会执行')
  })

  useEffect(() => {
    console.log('只在组件初次渲染的时候执行一次')
  }, [])

  useEffect(() => {
    console.log('count改变的时候执行')
  }, [count])

  return (
    <div>
      <button onClick={() => {setCount(count + 1)}}>{count}</button>
    </div>
  )
}

export default Home

4、useEffect的回调函数

使用场景:在组件被销毁时,如果有些操作需要被清理,就可以使用特定语法,比如清理定时器

import { useState, useEffect } from 'react'

function Counter() {
  useEffect(() => {
    let timer = setInterval(() => {
      console.log('定时器执行了')
    }, 1000)
    return () => {
      // 清理定时器
      clearInterval(timer)
    }
  }, [])

  return <p>this is text</p>
}

function Home() {
  const [flag, setFlag] = useState(true)
  return (
    <div>
      {flag ? <Counter></Counter> : null}
      <button onClick={() => setFlag(!flag)}>switch</button>
    </div>
  )
}

export default Home

5、useRef

通过ref绑定要获取的元素或者组件,执行useRef函数并传入null,返回值为一个对象,内部有一个current属性存放拿到的dom对象(组件实例)

  • 注意:函数组件由于没有实例,不能使用ref获取,如果想获取组件实例,必须是类组件
import { useEffect, useRef } from 'react'

function Home() {
  const h1Ref = useRef(null)

  // useEffect是在dom渲染之后才执行
  useEffect(() => {
    console.log(h1Ref)
  }, [])

  return (
    <div>
      <h1 ref={h1Ref}>this is h1</h1>
    </div>
  )
}

export default Home

6、useContext

实现步骤:使用createContext创建Context对象,在顶层组件通过Provider提供数据,在底层组件通过useContext函数获取数据

  1. const xxx = React.createContext();创建一个context
  2. <xxx.Provider value={[ num, setNum ]}>父组件设置要传递的值
  3. const [ num, setNum ] = React.useContext(xxx);子组件下使用

import { useContext, useState, createContext } from 'react'

const Context = createContext()

// 子组件A
function ComA() {
  const [count, name] = useContext(Context)
  return (
    <div>
      this is ComA
      <h2>A组件中接受到的count:{count}</h2>
      <h2>A组件中接受到的name:{name}</h2>
      <ComB></ComB>
    </div>
  )
}
// 孙组件B
function ComB() {
  const [count, name] = useContext(Context)
  return (
    <div>
      <p>this is ComB</p>
      <h2>B组件中接受到的count:{count}</h2>
      <h2>B组件中接受到的name:{name}</h2>
    </div>
  )
}
// 父组件
function Home() {
  const [count, setCount] = useState(20)
  const [name, setName] = useState('Tom')

  const change = () => {
    setCount(count + 1)
    setName('Jack')
  }

  return (
    <Context.Provider value={[count, name]}>
      <div>
        <ComA></ComA>
        <button onClick={change}>click</button>
      </div>
    </Context.Provider>
  )
}

export default Home