隨着不久前 React@16.8.0 的發佈,Hooks 也算是正式來到了幕前。我的以爲對React來講,Hooks 能夠算是一個里程碑式的功能。本文不會詳細介紹 Hooks,若是對 Hooks 還不是很瞭解的,能夠先看下 Introducing Hooks。javascript
簡單來講 Hooks 帶來了能夠在 Function Components 使用 state 和其它 React 特性的能力。而這帶來的第一個很直觀的好處就是原來寫的 Function Components 由於需求變更須要增長 state 時,不再須要重構成 Class Components 了(重構再也不是火葬場了)。html
我的認爲 Hooks 帶來的最大益處就是可以幫咱們更好地組織業務代碼,提升代碼複用率。咱們經過一個例子來講明,假設有這麼一個需求:「組件須要根據瀏覽器寬度的變化,來顯示不一樣的內容」。java
咱們先用 Class Component 來實現:react
export default class ResizeClassComponent extends React.Component {
constructor(props) {
super(props);
this.resizeHandler = null;
this.state = {
width: window.innerWidth,
}
}
componentDidMount() {
this.resizeHandler = () => {
this.setState({
width: window.innerWidth
})
}
window.addEventListener('resize', this.resizeHandler);
}
componentWillUnmount() {
window.removeEventListener('resize', this.resizeHandler);
}
render() {
const { width } = this.state;
return (
<div>width: {width}</div>
)
}
}
複製代碼
目前來看沒什麼問題,可是若是說如今又有一個組件須要實現這個功能,同樣的代碼再寫一遍?那若是有不少組件都須要這個功能呢?每次都寫一遍確定不現實,有人會說用render props
或者高階組件
來處理這個問題,那就讓咱們來實現一下:git
// render props
class ResizeRenderProps extends React.Component {
constructor(props) {
super(props);
this.resizeHandler = null;
this.state = {
width: window.innerWidth,
}
}
componentDidMount() {
this.resizeHandler = () => {
this.setState({
width: window.innerWidth
})
}
window.addEventListener('resize', this.resizeHandler);
}
componentWillUnmount() {
window.removeEventListener('resize', this.resizeHandler);
}
render() {
return this.props.children(this.state.width);
}
}
export default class ResizeClassComponent extends React.Component {
render() {
return (
<ResizeRenderProps> {width => <div>width: {width}</div>} </ResizeRenderProps>
)
}
}
複製代碼
// 高階組件
function withResize(WrappedComponent) {
return class ResizeHoc extends React.Component {
constructor(props) {
super(props);
this.resizeHandler = null;
this.state = {
width: window.innerWidth,
}
}
componentDidMount() {
this.resizeHandler = () => {
this.setState({
width: window.innerWidth
})
}
window.addEventListener('resize', this.resizeHandler);
}
componentWillUnmount() {
window.removeEventListener('resize', this.resizeHandler);
}
render() {
return <WrappedComponent width={this.state.width} />; } } } export default withResize(class ResizeClassComponent extends React.Component { render() { return ( <div>width: {this.props.width}</div> ) } }) 複製代碼
雖然實現了功能,可是兩種方式都不可避免地對原來組件作了重構,而且增長了一個層級,若是用的多了就會致使「wrapper hell」,拋開這個不談,render props
和高階組件
自己自帶的複雜度就不夠友好。github
那麼 Hooks 是怎麼解決的呢?瀏覽器
import React, { useState, useEffect } from 'react';
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const resizeHandler = () => setWidth(window.innerWidth);
window.addEventListener('resize', resizeHandler);
return () => window.removeEventListener('resize', resizeHandler)
})
return width;
}
export default function ResizeHooks() {
const width = useWindowWidth();
return (
<div>width: {width}</div>
)
}
複製代碼
是否是感受簡單又清楚?只須要自定義一個 Hook(其實也就是一個普通的函數啦,只不過用了內置的幾個Hook),使用的時候就像調用一個普通的函數同樣,沒有複雜的概念須要理解。正如前面所說,Hooks 能夠幫助咱們組織代碼,讓相關性的代碼都在一塊,而不是像在 Class Components 裏散落在各個生命週期函數中,貼個圖方便理解:app
圖片來源:twitter.com/prchdk/stat…函數
從圖中能夠發現邏輯相關的代碼都被單獨抽成了一個個 Hook,這意味着這部分有狀態的邏輯(stateful logic)能夠被複用,並且更容易理解。測試
稍微解釋下什麼叫「有狀態的邏輯(stateful logic)」,這裏的狀態指的就是 React 的 state,對應的無狀態的邏輯就是普通的函數啦。在 Hooks 以前,若是要複用這種有狀態的邏輯,除了上述的 render props
和高階組件
以外就沒有別的更簡單直接的辦法了。而有了 Hooks 以後,這部分邏輯可以被單獨抽離出,職責更明確,從而使複用更加簡單,代碼更加清晰,並且也更便於測試。
不知道我說的這些有沒有引發你對 Hooks 的興趣呢?其實從 React 官方的態度能夠看出是比較傾向於 Hooks 的,或者說是 Function Components,雖說是不會移除掉 Class Components(要是移除了,估計就炸了吧),可是能夠在項目中先小範圍試用下嘛,相信我你會喜歡上它的!
前面寫的有點分散,最後再總結一下 Hooks 帶來的開發體驗上的提高:
render props
和高階組件
,提供了更簡單直觀複用有狀態的邏輯(stateful logic)的方法有了 Hooks 以後,Function Components 再也不是「高級字符串模版」啦!😝
以上只是我我的對 React Hooks 的一些想法,若有不對之處,歡迎指正~~
擴展閱讀: