面試官:說(shuō)說(shuō)對(duì)React Hooks的理解?解決了什么問(wèn)題?
本文轉(zhuǎn)載自微信公眾號(hào)「JS每日一題」,作者灰灰。轉(zhuǎn)載本文請(qǐng)聯(lián)系JS每日一題公眾號(hào)。
一、是什么
Hook 是 React 16.8 的新增特性。它可以讓你在不編寫(xiě) class 的情況下使用 state 以及其他的 React 特性
至于為什么引入hook,官方給出的動(dòng)機(jī)是解決長(zhǎng)時(shí)間使用和維護(hù)react過(guò)程中常遇到的問(wèn)題,例如:
- 難以重用和共享組件中的與狀態(tài)相關(guān)的邏輯
- 邏輯復(fù)雜的組件難以開(kāi)發(fā)與維護(hù),當(dāng)我們的組件需要處理多個(gè)互不相關(guān)的 local state 時(shí),每個(gè)生命周期函數(shù)中可能會(huì)包含著各種互不相關(guān)的邏輯在里面
- 類組件中的this增加學(xué)習(xí)成本,類組件在基于現(xiàn)有工具的優(yōu)化上存在些許問(wèn)題
- 由于業(yè)務(wù)變動(dòng),函數(shù)組件不得不改為類組件等等
在以前,函數(shù)組件也被稱為無(wú)狀態(tài)的組件,只負(fù)責(zé)渲染的一些工作
因此,現(xiàn)在的函數(shù)組件也可以是有狀態(tài)的組件,內(nèi)部也可以維護(hù)自身的狀態(tài)以及做一些邏輯方面的處理
二、有哪些
上面講到,Hooks讓我們的函數(shù)組件擁有了類組件的特性,例如組件內(nèi)的狀態(tài)、生命周期
最常見(jiàn)的hooks有如下:
- useState
- useEffect
- 其他
useState
首先給出一個(gè)例子,如下:
- import React, { useState } from 'react';
- function Example() {
- // 聲明一個(gè)叫 "count" 的 state 變量
- const [count, setCount] = useState(0);
- return (
- <div>
- <p>You clicked {count} times</p>
- <button onClick={() => setCount(count + 1)}>
- Click me
- </button>
- </div>
- );
- }
在函數(shù)組件中通過(guò)useState實(shí)現(xiàn)函數(shù)內(nèi)部維護(hù)state,參數(shù)為state默認(rèn)的值,返回值是一個(gè)數(shù)組,第一個(gè)值為當(dāng)前的state,第二個(gè)值為更新state的函數(shù)
該函數(shù)組件等價(jià)于的類組件如下:
- class Example extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- count: 0
- };
- }
- render() {
- return (
- <div>
- <p>You clicked {this.state.count} times</p>
- <button onClick={() => this.setState({ count: this.state.count + 1 })}>
- Click me
- </button>
- </div>
- );
- }
- }
從上述兩種代碼分析,可以看出兩者區(qū)別:
- state聲明方式:在函數(shù)組件中通過(guò) useState 直接獲取,類組件通過(guò)constructor 構(gòu)造函數(shù)中設(shè)置
- state讀取方式:在函數(shù)組件中直接使用變量,類組件通過(guò)this.state.count的方式獲取
- state更新方式:在函數(shù)組件中通過(guò) setCount 更新,類組件通過(guò)this.setState()
總的來(lái)講,useState 使用起來(lái)更為簡(jiǎn)潔,減少了this指向不明確的情況
useEffect
useEffect可以讓我們?cè)诤瘮?shù)組件中進(jìn)行一些帶有副作用的操作
同樣給出一個(gè)計(jì)時(shí)器示例:
- class Example extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- count: 0
- };
- }
- componentDidMount() {
- document.title = `You clicked ${this.state.count} times`;
- }
- componentDidUpdate() {
- document.title = `You clicked ${this.state.count} times`;
- }
- render() {
- return (
- <div>
- <p>You clicked {this.state.count} times</p>
- <button onClick={() => this.setState({ count: this.state.count + 1 })}>
- Click me
- </button>
- </div>
- );
- }
- }
從上面可以看見(jiàn),組件在加載和更新階段都執(zhí)行同樣操作
而如果使用useEffect后,則能夠?qū)⑾嗤倪壿嫵殡x出來(lái),這是類組件不具備的方法
對(duì)應(yīng)的useEffect示例如下:
- import React, { useState, useEffect } from 'react';
- function Example() {
- const [count, setCount] = useState(0);
- useEffect(() => { document.title = `You clicked ${count} times`; });
- return (
- <div>
- <p>You clicked {count} times</p>
- <button onClick={() => setCount(count + 1)}>
- Click me
- </button>
- </div>
- );
- }
useEffect第一個(gè)參數(shù)接受一個(gè)回調(diào)函數(shù),默認(rèn)情況下,useEffect會(huì)在第一次渲染和更新之后都會(huì)執(zhí)行,相當(dāng)于在componentDidMount和componentDidUpdate兩個(gè)生命周期函數(shù)中執(zhí)行回調(diào)
如果某些特定值在兩次重渲染之間沒(méi)有發(fā)生變化,你可以跳過(guò)對(duì) effect 的調(diào)用,這時(shí)候只需要傳入第二個(gè)參數(shù),如下:
- useEffect(() => {
- document.title = `You clicked ${count} times`;
- }, [count]); // 僅在 count 更改時(shí)更新
上述傳入第二個(gè)參數(shù)后,如果 count 的值是 5,而且我們的組件重渲染的時(shí)候 count 還是等于 5,React 將對(duì)前一次渲染的 [5] 和后一次渲染的 [5] 進(jìn)行比較,如果是相等則跳過(guò)effects執(zhí)行
回調(diào)函數(shù)中可以返回一個(gè)清除函數(shù),這是effect可選的清除機(jī)制,相當(dāng)于類組件中componentwillUnmount生命周期函數(shù),可做一些清除副作用的操作,如下:
- useEffect(() => {
- function handleStatusChange(status) {
- setIsOnline(status.isOnline);
- }
- ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
- return () => {
- ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
- };
- });
所以, useEffect相當(dāng)于componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個(gè)生命周期函數(shù)的組合
其它 hooks
在組件通信過(guò)程中可以使用useContext,refs學(xué)習(xí)中我們也用到了useRef獲取DOM結(jié)構(gòu)......
還有很多額外的hooks,如:
- useReducer
- useCallback
- useMemo
- useRef
三、解決什么
通過(guò)對(duì)上面的初步認(rèn)識(shí),可以看到hooks能夠更容易解決狀態(tài)相關(guān)的重用的問(wèn)題:
- 每調(diào)用useHook一次都會(huì)生成一份獨(dú)立的狀態(tài)
- 通過(guò)自定義hook能夠更好的封裝我們的功能
編寫(xiě)hooks為函數(shù)式編程,每個(gè)功能都包裹在函數(shù)中,整體風(fēng)格更清爽,更優(yōu)雅
hooks的出現(xiàn),使函數(shù)組件的功能得到了擴(kuò)充,擁有了類組件相似的功能,在我們?nèi)粘J褂弥?,使用hooks能夠解決大多數(shù)問(wèn)題,并且還擁有代碼復(fù)用機(jī)制,因此優(yōu)先考慮hooks
參考文獻(xiàn)
https://zh-hans.reactjs.org/docs/hooks-state.html
https://zh-hans.reactjs.org/docs/hooks-effect.html
https://www.cnblogs.com/lalalagq/p/9898531.html