React Hooks的使用

395 阅读3分钟

什么是Hooks

我们知道,React的组件创建方式有两种:(1)类式组件(2)函数式组件。

  • 类式组件能够对状态的管理与切换进行操控,但是在简单的页面中使用类式组件会使代码显得很重,并且状态逻辑难以复用。即便是使用 render props (渲染属性)和高阶组件可以优化,但是这两种方式都会将原来的组件用一个容器包裹起来,形成层级嵌套,代码冗余。此外,在类式组件中,this的指向问题也值得思考。
  • 函数式组件没有了类式组件中的状态,没有生命周期,更不存在this。但是为了对状态进行管理等,就有了hooks。

React Hook就是将组件写成纯函数的形式,在需要一些特定的功能时,就将特定的hook钩子引进来,并且可以在此基础上封装我们自定义的hook。

常用的Hooks

useState()

我们知道,纯函数组件是没有state的,但是为了能够操控数据,useState()为函数式组件注入了状态。 示例:

import React, { useState } from 'react'

function App() {
    const [count, setCount] = useState(0)
    const add = () => {
        setCount(count + 1)
    }
    return (
        <div className="App">
            <div>Count: {count}</div>
            <button onClick={add}>点击+1</button>
        </div>
    )
}

export default App

useState()创建一个状态,可以赋一个初始值,用一个数组来接收,数组的第一项即为创建的状态变量,数组的第二项是一个函数,用于修改状态变量的值。其中,这个setCount函数可以有多种写法,上面的写法是其中一种,还可以在里面写一个函数,函数的返回值就是要进行状态修改的操作。

    setCount((count) => {
        return count + 1
    })
    // 简写
    setCount(count => count + 1)

值得注意的是,当useState里面的状态为一个对象时,useState是不会进行局部更新的,而是将修改后的内容将之前的内容进行覆盖。 示例:

import React,{useState} from 'react'

function App(){
  const [user,setUser] = useState({name: 'tom', age: 18})
  const changeName = () => {
      setUser({
          ...user,
          name:'jack'
      })
  }
  return (
    <div className='App'>
        <h1>{user.name}</h1>
        <h1>{user.age}</h1>
        <button onClick={changeName}>Click</button>
    </div>
  )
 }
 
 export default App

从setUser的写法我们也不难看出,这里是用修改后的name将原来的name进行一个覆盖,然后再生成了一个新的user对象。

useRef()

useRef用于获取真的的DOM节点,返回一个对象,里面有current属性存放着获取到的DOM对象。 示例:

import React, { useRef } from 'react'

function App() {
    const myRef = useRef()
    const handleClick = () => {
        console.log(myRef.current)
    }
    return (
        <div className="App">
            <input ref={myRef} type="text" />
            <button onClick={handleClick}>点击打印</button>
        </div>
    )
}

export default App

useEffect()

useEffect 可以检测数据的更新,更好的处理异步请求等副作用。useEffect接收两个参数,第一个参数为要进行的异步操作,第二个参数为一个数组,里面为要检测的依赖项,只要数组里面的依赖项发生了变化,useEffect就会执行。当第二个参数不传时,在每次组件渲染时useEffect都会执行,类似于 componentDidUpdate 生命周期钩子。第一个参数返回的函数就相当于componentWillUnmont.

// useEffect 可以模拟三个生命周期钩子
  useEffect(() => {
    let timer = setInterval(() => {
      setCount(count => count + 1)
    }, 1000)
    return () => {
      clearInterval(timer)
    }
  }, [count])
  // 第一个参数返回的函数就相当于 componentWillUnmont
  // 第二个参数为要检测的数组,谁要检测就传谁
  // 若不传第二个参数,则相当于 componentDidUpdate,传了相当于 componentDidMount

useContext()

context 有上下文的意思,所以 useContext() 常用于组件之间的数据状态共享,避免了逐级传递props的缺陷。通过 createContext 来创建 context 对象,然后使用 context 对象上的 Procider 来提供数据,在后代组件中通过 useContext 来接收数据。 示例:

import { createContext, useContext } from 'react';

const ThemeContext = createContext(null);

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}

function Form() {
  return (
    <Panel title="Welcome">
      <Button>Sign up</Button>
      <Button>Log in</Button>
    </Panel>
  );
}

function Panel({ title, children }) {
  const theme = useContext(ThemeContext);
  const className = 'panel-' + theme;
  return (
    <section className={className}>
      <h1>{title}</h1>
      {children}
    </section>
  )
}

function Button({ children }) {
  const theme = useContext(ThemeContext);
  const className = 'button-' + theme;
  return (
    <button className={className}>
      {children}
    </button>
  );
}

总结

React Hooks 能够让我们在函数式组件中灵活的编写状态和功能等,避免了类式组件中存在的一些问题。这里只列举了部分的hook,还有一些重要的hooks在React官方文档都有详细的说明。