Hooks
出了有段時間了,不知盆友們有在項目中開始使用了嗎❓若是還沒了解的童鞋,能夠瞧瞧這篇文章,對比看下三大基礎 Hooks
和傳統 class
組件的區別和用法吧😙html
咱們所指的三個基礎 Hooks
是:react
useState
在函數式組件內維護 state
useEffect
函數式組件內有反作用的調用與 componentDidMount
、componentDidUpdate
相似但又有所區別useContext
監聽 provider 更新變化useState
容許咱們在函數式組件中維護 state
,傳統的作法須要使用類組件。舉個例子🌰,咱們須要一個輸入框,隨着輸入框內容的改變,組件內部的 label
標籤顯示的內容也同時改變。下面是兩種不一樣的寫法:json
不使用 useState:markdown
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> ) } } 複製代碼
React.Component
處繼承state
state
的方法render
函數返回 JSX
✅使用 useState:async
// 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; 複製代碼
react
中引入 useState
這個📦useState
方法,接收一個初始化參數,定義 state
變量,以及改變 state
的方法state
這個變量便可,增長事件處理函數觸發改變 state
的方法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
是專門用來處理反作用的,獲取數據、建立訂閱、手動更改 DOM 等這都是反作用。你能夠想象它是 componentDidMount
和 componentDidUpdate
及 componentWillUnmount
的結合。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> ) } 複製代碼
react
中引入 useEffect
😳getData
方法handleClick
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> ) } } 複製代碼
ClassTest
state
componentDidMount
和 componentDidUpdate
階段改變 document.title
render
函數渲染這一堆東西寫完人都睡着了💤
使用 useEffect 不只去掉了部分沒必要要的東西,並且合併了 componentDidMount
和 componentDidUpdate
方法,其中的代碼只須要寫一遍。😀
第一次渲染和每次更新以後都會觸發這個鉤子,若是須要手動修改自定義觸發規則
見文檔:https://zh-hans.reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
另外,官網還給了一個訂閱清除訂閱的例子:
使用 useEffect
直接 return
一個函數便可:
返回的函數是選填的,可使用也能夠不使用:
文檔:https://zh-hans.reactjs.org/docs/hooks-effect.html#recap
比方說咱們使用 useEffect 來解綁事件處理函數:
useEffect(() => { window.addEventListener('keydown', handleKeydown); return () => { window.removeEventListener('keydown', handleKeydown); } }) 複製代碼
useContext
的最大的改變是能夠在使用 Consumer
的時候沒必要在包裹 Children
了,比方說咱們先建立一個上下文,這個上下文裏頭有一個名爲 username
的 state
,以及一個修改 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 複製代碼
看看咱們作了什麼:
createContext
建立了上下文Provider
;裏頭定義了 handleChangeUsername
方法和 username
的 state
,並返回一個包裹 this.props.children
的 Provider
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; 複製代碼
看看作了啥:
useContext
UserProvider
以及上下文 UserContext
useContext
方法獲取 state
UserProvider
嵌套主 children
這樣經過 useContext
和 useState
就重構完畢了,看起來代碼又少了很多😄
以上,三個基礎的 Hooks
入門就講解完畢了,上手就是這樣,函數式組件和 Hooks
配合使用真的很是爽⛄
參考: