🔱 快速上手三大基礎 React Hooks

Hooks 出了有段時間了,不知盆友們有在項目中開始使用了嗎❓若是還沒了解的童鞋,能夠瞧瞧這篇文章,對比看下三大基礎 Hooks 和傳統 class 組件的區別和用法吧😙html

咱們所指的三個基礎 Hooks 是:react

  • useState 在函數式組件內維護 state
  • useEffect 函數式組件內有反作用的調用與 componentDidMountcomponentDidUpdate 相似但又有所區別
  • useContext 監聽 provider 更新變化

useState

useState 容許咱們在函數式組件中維護 state,傳統的作法須要使用類組件。舉個例子🌰,咱們須要一個輸入框,隨着輸入框內容的改變,組件內部的 label 標籤顯示的內容也同時改變。下面是兩種不一樣的寫法:json

不使用 useStatemarkdown

import React from "react";
// 1
export class ClassTest extends React.Component {
  // 2
  state = {
    username: this.props.initialState
  }
  // 3
  changeUserName(val) {
    this.setState({ username: val })
  }
  // 4
  render() {
    return (
      <div> <label style={{ display: 'block' }} htmlFor="username">username: {this.state.username}</label> <input type="text" name="username" onChange={e => this.changeUserName(e.target.value)} /> </div> ) } } 複製代碼
  1. 咱們須要定義一個類並從 React.Component 處繼承
  2. 還須要初始化一個 state
  3. 初始化改變 state 的方法
  4. 最後還要使用 render 函數返回 JSX

✅使用 useStateasync

// 1
import React, { useState } from "react";

export function UseStateTest({ initialState }) {
  // 2
  let [username, changeUserName] = useState(initialState)
  // 3
  return (
    <div> <label style={{ display: 'block' }} htmlFor="username">username: {username}</label> <input type="text" name="username" onChange={e => changeUserName(e.target.value)} /> </div> ) } 複製代碼

在父組件中使用:ide

import React from "react";
// 引入組件
import { UseStateTest } from './components/UseStateTest'

// 4
const App = () => (
  <div> <UseStateTest initialState={'initial value'} /> </div> ) export default App; 複製代碼
  1. 須要從 react 中引入 useState 這個📦
  2. 使用 useState 方法,接收一個初始化參數,定義 state 變量,以及改變 state 的方法
  3. 在須要使用的地方直接使用 state 這個變量便可,增長事件處理函數觸發改變 state 的方法
  4. 在父組件中調用,經過 props 傳遞 initialState 初始化值

useState 方法替換掉原有的 class 不只性能會有所提高,並且能夠看到代碼量減小不少,而且再也不須要使用 this,因此可以維護 state 的函數式組件真的很好用😀函數

  • class classTest extends React.Components {} 🔜 function UseStateTest(props) {} 函數式組件寫法
  • this.state.username 🔜 username 使用 state 不須要 this
  • this.setState({ username: '' }) 🔜 changeUserName('') 改變 state 也不須要書寫 setState 方法

文檔說明:https://zh-hans.reactjs.org/docs/hooks-state.html性能

useEffect

useEffect 是專門用來處理反作用的,獲取數據、建立訂閱、手動更改 DOM 等這都是反作用。你能夠想象它是 componentDidMountcomponentDidUpdatecomponentWillUnmount 的結合。fetch

舉個例子🌰🌰,比方說咱們建立一個 div 標籤,每當點擊就會發送 http 請求並將頁面 title 改成對應的數值:ui

import React from 'react'
// 1
import { useState, useEffect } from 'react'

export function UseEffectTest() {
    let [msg, changeMsg] = useState('loading...')
    // 2
    async function getData(url) { // 獲取 json 數據
        return await fetch(url).then(d => d.json())
    }
    // 3
    async function handleClick() { // 點擊事件改變 state
        let data = await getData('https://httpbin.org/uuid').then(d => d.uuid)
        changeMsg(data)
    }
    // 4
    useEffect(() => { // 反作用
        document.title = msg
    })
    return (
        <div onClick={() => handleClick()}>{msg}</div>
    )
}
複製代碼
  1. 首先從 react 中引入 useEffect 😳
  2. 而後建立獲取數據的 getData 方法
  3. 建立事件處理函數 handleClick
  4. 使用 useEffect 處理反作用:改變頁面的 title

若是使用傳統的類組件的寫法:

import React from 'react'
// 1
export class ClassTest extends React.Component {
    // 2
    state = {
        msg: 'loading...'
    }
    // 3
    async getData(url) { // 獲取 json 數據
        return await fetch(url).then(d => d.json())
    }
    handleClick = async () => { // 點擊事件改變 state
        let data = await this.getData('https://httpbin.org/uuid').then(d => d.uuid)
        this.setState({ msg: data })
    }
    // 4
    componentDidMount() {
        document.title = this.state.msg
    }
    componentDidUpdate() {
        document.title = this.state.msg
    }
    // 5
    render() {
        return (
            <div onClick={this.handleClick}>{this.state.msg}</div>
        )
    }
}
複製代碼
  1. 首先建立類 ClassTest
  2. 初始化 state
  3. 定義獲取數據方法和事件處理函數
  4. componentDidMountcomponentDidUpdate 階段改變 document.title
  5. 最後經過 render 函數渲染

這一堆東西寫完人都睡着了💤

使用 useEffect 不只去掉了部分沒必要要的東西,並且合併了 componentDidMountcomponentDidUpdate 方法,其中的代碼只須要寫一遍。😀

第一次渲染和每次更新以後都會觸發這個鉤子,若是須要手動修改自定義觸發規則

見文檔:https://zh-hans.reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects

另外,官網還給了一個訂閱清除訂閱的例子:

20190313113615.png

使用 useEffect 直接 return 一個函數便可:

20190313113627.png

返回的函數是選填的,可使用也能夠不使用:

20190313113753.png

文檔:https://zh-hans.reactjs.org/docs/hooks-effect.html#recap

比方說咱們使用 useEffect 來解綁事件處理函數:

useEffect(() => {
    window.addEventListener('keydown', handleKeydown);
    return () => {
        window.removeEventListener('keydown', handleKeydown);
    }
})
複製代碼

useContext

useContext 的最大的改變是能夠在使用 Consumer 的時候沒必要在包裹 Children 了,比方說咱們先建立一個上下文,這個上下文裏頭有一個名爲 usernamestate,以及一個修改 username 的方法 handleChangeUsername

建立上下文

不使用 useState:

不使用 state hooks 的代碼以下:

import React, { createContext } from 'react'

// 1. 使用 createContext 建立上下文
export const UserContext = new createContext()

// 2. 建立 Provider
export class UserProvider extends React.Component {

    handleChangeUsername = (val) => {
        this.setState({ username: val })
    }

    state = {
        username: '',
        handleChangeUsername: this.handleChangeUsername
    }

    render() {
        return (
            <UserContext.Provider value={this.state}> {this.props.children} </UserContext.Provider> ) } } // 3. 建立 Consumer export const UserConsumer = UserContext.Consumer 複製代碼

看看咱們作了什麼:

  1. 首先咱們使用 createContext 建立了上下文
  2. 而後咱們建立 Provider;裏頭定義了 handleChangeUsername 方法和 usernamestate,並返回一個包裹 this.props.childrenProvider
  3. 最後咱們再返回 UserContext.Consumer

代碼比較冗長,可使用上文提到的 useState 對其進行精簡:

✅使用 useState:

使用 state hooks

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

// 1. 使用 createContext 建立上下文
export const UserContext = new createContext()

// 2. 建立 Provider
export const UserProvider = props => {
    let [username, handleChangeUsername] = useState('')
    return (
        <UserContext.Provider value={{username, handleChangeUsername}}> {props.children} </UserContext.Provider> ) } // 3. 建立 Consumer export const UserConsumer = UserContext.Consumer 複製代碼

使用 useState 建立上下文更加簡練。

使用上下文

上下文定義完畢後,咱們再來看使用 useContext 和不使用 useContext 的區別是啥🎁:

不使用 useContext:

import React  from "react";
import { UserConsumer, UserProvider } from './UserContext'

const Pannel = () => (
  <UserConsumer> {/* 不使用 useContext 須要調用 Consumer 包裹 children */} {({ username, handleChangeUsername }) => ( <div> <div>user: {username}</div> <input onChange={e => handleChangeUsername(e.target.value)} /> </div> )} </UserConsumer> ) const Form = () => <Pannel></Pannel> const App = () => ( <div> <UserProvider> <Form></Form> </UserProvider> </div> ) export default App; 複製代碼

✅使用 useContext:

只須要引入 UserContext,使用 useContext 方法便可:

import React, { useContext }  from "react"; // 1
import { UserProvider, UserContext } from './UserContext' // 2

const Pannel = () => {
  const { username, handleChangeUsername } = useContext(UserContext) // 3
  return (
    <div> <div>user: {username}</div> <input onChange={e => handleChangeUsername(e.target.value)} /> </div> ) } const Form = () => <Pannel></Pannel> // 4 const App = () => ( <div> <UserProvider> <Form></Form> </UserProvider> </div> ) export default App; 複製代碼

看看作了啥:

  1. 首先第一步引入useContext
  2. 而後引入 UserProvider 以及上下文 UserContext
  3. 再須要使用的組件中調用 useContext 方法獲取 state
  4. 固然前提是要在父組件中使用 UserProvider 嵌套主 children

這樣經過 useContextuseState 就重構完畢了,看起來代碼又少了很多😄

以上,三個基礎的 Hooks 入門就講解完畢了,上手就是這樣,函數式組件和 Hooks 配合使用真的很是爽⛄

參考:

  • https://codeburst.io/quick-intro-to-react-hooks-6dd8ecb898ed
  • https://reactjs.org/docs/hooks-reference.html

相關文章
相關標籤/搜索