好巧不巧,工作了一年跳槽了,之前用的vue,現在用的react~ 嗯!工作使人進步!現在開始學react吧!
切入正題~
react hooks是React16.8.0之后出現的,
類組件存在的問題:
- this指向問題
- 生命周期繁瑣
- 創建類的實例開銷較大
而函數組件函數組件沒有this,沒有生命周期,沒有狀態state,函數的執行開銷比創建類實例的開銷要小。
因此,為了提高性能,盡量使用函數組件。
然而函數組件有個最大的問題就是沒有狀態state,所以react官方出了個hooks來解決這個問題。
項目中最常用的幾個hook:
useState
1. useState最好寫到函數的起始位置,便於閱讀
2. useState嚴禁出現在代碼塊(判斷、循環)中
3. useState返回的函數(數組的第二項),引用不變(節約內存空間)
4. 使用函數改變數據,若數據和之前的數據完全相等(使用Object.is比較),不會導致重新渲染,以達到優化效率的目的。
5. 使用函數改變數據,若傳入的是值,只會保留最后一次的函數執行,若傳入的是函數,會在事件完成后統一執行。
import React, { useState } from 'react';// 引入state hook export default function App() { console.log("App render") const [n, setN] = useState(0); //使用一個狀態,該狀態的默認值是0 return <div> <button onClick={() => { setN(n - 1); setN(n - 2);// 傳入值,只會保留最后一次setN的執行 // setN(prevN => prevN - 1); // setN(prevN => prevN - 1);//傳入函數,在事件完成之后統一執行 }}>-</button> <span>{n}</span> </div> }
6. 如果要實現強制刷新組件
- 類組件:使用forceUpdate函數
- 函數組件:使用一個空對象的useState
類組件
import React, { Component } from 'react' export default class App extends Component { render() { return ( <div> <button onClick={()=>{ //不會運行shouldComponentUpdate this.forceUpdate();//強制重新渲染 }}>強制刷新</button> </div> ) } }
函數組件
import React, { useState } from 'react' export default function App() {
const [, forceUpdate] = useState({}); return <div> <p > <button onClick={() => { forceUpdate({}); }}>強制刷新</button> </p> </div> }
useEffect
它能在函數組件中執行副作用,並且它與 class 中的生命周期函數極為類似。
副作用:
1. ajax請求
2. 計時器
3. 其他異步操作
4. 更改真實DOM對象
5. 本地存儲
6. 其他會對外部產生影響的操作
- 副作用函數的運行時間點,是在頁面完成真實的UI渲染之后。因此它的執行是異步的,並且不會阻塞瀏覽器
與類組件中componentDidMount和componentDidUpdate的區別
componentDidMount和componentDidUpdate,更改了真實DOM,但是用戶還沒有看到UI更新,是同步的。
useEffect中的副作用函數,更改了真實DOM,並且用戶已經看到了UI更新,是異步的。
- 每個函數組件中,可以多次使用useEffect,但不要放入判斷或循環等代碼塊中。
- useEffect中的副作用函數,可以有返回值,返回值必須是一個函數,該函數叫做清理函數
在每次運行副作用函數之前,運行返回的函數
首次渲染組件不會運行
組件被銷毀時一定會運行
- useEffect函數,可以傳遞第二個參數
第二個參數是一個數組
數組中記錄該副作用的依賴數據
當組件重新渲染后,只有依賴數據與上一次不一樣時,才會執行副作用
所以,當傳遞了依賴數據之后,如果數據沒有發生變化
副作用函數僅在第一次渲染后運行,清理函數僅在卸載組件后運行
import React, { useState, useEffect } from 'react' function Test() { useEffect(() => { console.log("副作用函數,僅掛載時運行一次") return () => { console.log("清理函數,僅卸載時運行一次") }; }, []); //使用空數組作為依賴項,則副作用函數僅在掛載的時候運行 console.log("渲染組件"); const [, forceUpdate] = useState({}) return <h1>Test組件 <button onClick={() => { forceUpdate({}) }}>刷新組件</button></h1> } export default function App() { const [visible, setVisible] = useState(true) return ( <div> { visible && <Test /> } <button onClick={() => { setVisible(!visible); }}>顯示/隱藏</button> </div> ) }
useRef
useRef(value)返回一個對象:{current: value}
- 在每次渲染時返回同一個 ref 對象
- 變更 .current 屬性不會引發組件重新渲染
import React, { useRef } from 'react' export default function App() { console.log('app render') const nRef = useRef(10); // {current:10} return ( <div> <h1>{nRef.current}不會變</h1> <button onClick={() => {nRef.current--;console.log(nRef.current, 'nRef.current變化')}}>減少</button> </div> ) }