React16.8中Hooks詳解

水果哥發表於2019-04-20

一、React Hooks(鉤子)是什麼

Introducing Hooks

React哲學:一切皆元件

類元件

class Counter extends Component {
    render () {
        return "Hello World"
    }
}
複製程式碼

函式元件

const Counter = () => {
    return "Hello World"
}
複製程式碼

為什麼說函式式元件更優?

  1. 簡單易懂
  2. 更符合React哲學,可以理解為React就是一個畫UI的工具,符合UI=f(state)的原則
  3. 函數語言程式設計

有hooks之前,為什麼React需要類元件?

  1. 需要狀態(state)
class Counter extends Component {
    state = {
        count: 0
    }
}
複製程式碼
  1. 需要生命週期函式
shouldComponentUpdate () { // 減少render渲染
    return true
}
複製程式碼
  1. 需要副作用操作(非純函式)

副作用:呼叫ajax等

純函式:每次輸入的引數一樣,那麼每次返回的結果都相同。不要改全域性變數,不要做ajax請求,不要去做非同步操作等

componentDidMount () {
    fetchAPI().then(res => {
        this.setState({count: res})
    })
}
複製程式碼

能否讓函式元件擁有這些功能?

const Counter = () => {
    return `
    想擁有,可是我沒辦法擁有狀態,也沒有生命週期函式,更不要說副作用操作了
    `
}
複製程式碼

Hooks擁有了這些功能

useState 狀態管理
useEffect 生命週期函式
useContext 
等等...
複製程式碼

二、React Hooks帶來哪些好處

useState: 在函式中管理狀態

const Counter = () => {
    const [count, setCount] = useState(0) // 解構  初始值0
    const increment = () => setCount( count + 1 )
    return (
      <>
        <h1>{count}</h1>
        <button onClick={increment}>+</button>
      </>
    )
}
複製程式碼

useState的返回值是什麼?

const [count, setCount] = useState(0)
可以改為下面的寫法:
const state = useState(0)
const count = state[0]
const setCount = state[1]
複製程式碼

三、常用 Hooks 使用技巧

HoC : Higher order Component(With開頭)

有了useState這個hook之後,就可以在元件裡管理狀態了

useState 一般寫在函式的最上面
useState:返回結果可以任意取名
const [count, setCount] = useState(0)
也可寫成
const  [count, updateCount] = useState(0)

useState是怎麼做到的?
想象一下React為每一次useState呼叫分配一個“空間”
React通過useState呼叫順序辨別各個“空間”,很簡單,就是通過呼叫順序來區分的!
複製程式碼

useState執行順序必須一致!

不能寫在if判斷裡,如下

const Counter = () => {
    const [count, setCount] = useState(0)
    if (count % 2 === 0) {
        const [bar, setBar] = useState(null) // 不能這麼寫
    }
    const [foo, setFoo] = useState("foo")
}


const [count, setCount] = useState(0) // 兩個useState 根據呼叫順序區分
const [name, setName] = useState("Fruit Bro") // 兩個useState 根據呼叫順序區分

setCount(count + 1)
setCount也是非同步的,是setState的變種!
複製程式碼

useEffect:有機會做副作用操作

componentDidMount 用於在mount過程結束時的副作用
componentDidUpdate 用於在update過程結束時的副作用

useEffect = componentDidMount + componentDidUpdate
複製程式碼

useEffect模擬componentDidMount

useEffect(() => {
    // 每次mount或update都會呼叫到這裡
})

useEffect(() => {
    // 只有mount時呼叫這裡
},[]) // []代表依賴的資料
複製程式碼

useEffect模擬componentDidUnmount

useEffect(() => {
    // 只有mount時呼叫這裡
    return () => {
        // 只有unmount時呼叫這裡
    }
},[])
複製程式碼

hooks特有而類元件沒有的是componentDidUnupdate,類似componentDidUnmount

useEffect模擬componentDidUpdate

const mounted = useRef() // useRef()不管呼叫多少次,返回的結果完全是一樣的
useEffect(() => {
  if (!mounted.current) { 
  // 初次mounted,其實有用的就是current
      mounted.current = true
  } else {
      // do componentDidUpdate logic
  }
})
複製程式碼

ref可以訪問真正的dom,但在React中,是非常介意直接操作真實DOM的,因此用vitural dom

注意:每一次渲染都有獨立的props和state,每一次渲染使用hooks,函式元件的每一次渲染,無論是mount還是update,不管是第幾次update,它都有獨立的props和state

const Counter = () => {
    const [count, setCount] = useState(0)
    const onClick = () => {
        setCount(count + 1)
        setTimeout(() => {
        // 返回0的原因,初次為0,只有再次渲染的時候count才會為1,而每次渲染都有獨立的props和state,因此新的渲染不會影響上一次的值
            alert(count) // 0 每一次新的執行就是一次新的開始
        }, 1000)
    }
    return (
      <>
        <h1>{count}</h1>
        <button onClick={onClick}>+</button>
      </>
    )
}
複製程式碼

useContext: 簡化Context的使用

Hooks之前
<Context.Consumer>
  {contextValue => <h1>{contextValue}</h1>}
</Context.Consumer>

Hooks之後
const contextValue = useContext(Context)

<h1>{contextValue}</h1>
複製程式碼

四、React Hooks有哪些好處

Hooks的好處

  1. 降低了元件的複雜性

    1.1 完全使用函式元件

    1.2 無需生命週期函式

    1.3 更好的狀態管理

  2. 更好的程式碼重用性

    2.1 傳統的程式碼重用方式 元件、高階元件(HoC)、render props模式

    2.2 Hooks下的程式碼重用方式:函式

定製Hooks: 函式形式的程式碼重用
// Beacon 計數
const useBeacon = () => {
    const [renderCount, setRenderCount] = useState(0)
    
    useEffect(() => {
        sendBeacon()
    })
}
// 重用
const Foo = () => {
    useBeacon();
    ...
}

const Bar = () => {
    useBeacon();
    ...
}
複製程式碼

五、如何遷移到Hooks

React v16.8.0開始正式支援Hooks

原有類元件功能依然支援

業界趨勢將是向函式元件傾斜

遷移策略

瞭解Hooks

對新組建使用Hooks

逐步替換原有類元件

hooks如何處理類元件的shouldComponentUpdate來做效能優化 memo

如有錯誤,歡迎指正!謝謝!

相關文章