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
配合使用真的很是爽⛄
参考: