React函數類組件及其Hooks學習


函數類組件

函數式組件和類式組件的區別:

React組件可以分為類組件和函數式組件,兩者最明顯的不同就是在語法上,函數組件是一個純函數,它接收一個props對象返回一個react元素。而類組件需要去繼承React.Component並且創建render函數返回react元素,這將會要更多的代碼,雖然它們實現的效果相同。

  1. 函數式組件中沒有state
  2. 函數式組件中沒有生命周期(重點,涉及到生命周期的方法只能在類組件中定義。)

在較新的react版本看中添加了hooks,使得我們可以在函數組件中使用useState鈎子去管理state,使用useEffect鈎子去使用生命周期函數。從這個改版中我們可以看出作者更加看重函數組件,而且react團隊曾提及到在react之后的版本將會對函數組件的性能方面進行提升。

為什么要使用函數式組件?

  1. Hooks是比高階組件(HOC)和render props更優雅的邏輯復用方式。這個是很多人喊“真香”的原因。優雅的邏輯復用方式,會促進一個更加蓬勃的生態,這對於原本生態就很強的React來說是如虎添翼。會有更多的人願意把自己的邏輯抽離成hooks(因為真的太優雅了),發布為library,為react生態添磚加瓦(看看這段時間各種基於hooks的狀態管理工具)。我還認為,很快會出現一些“hooks生態圈”的“lodash”。
  2. 函數式組件的心智模型更加“聲明式”。hooks(主要是useEffect)取代了生命周期的概念(減少API),讓開發者的代碼更加“聲明化”:
  • 舊的思維:“我在這個生命周期要檢查props.A和state.B(props和state),如果改變的話就觸發xxx副作用”。這種思維在后續修改邏輯的時候很容易漏掉檢查項,造成bug。
  • 新的思維:“我的組件有xxx這個副作用,這個副作用依賴的數據是props.A和state.B”。從過去的命令式轉變成了聲明式編程。
  • 其實仔細想一想,人們過去使用生命周期不就是為了判斷執行副作用的時機嗎?現在hooks直接給你一個聲明副作用的API,使得生命周期變成了一個“底層概念”,無需開發者考慮。開發者工作在更高的抽象層次上了。
  • 類似的道理,除了聲明副作用的API,react還提供了聲明“密集計算”的API(useMemo),取代了過去“在生命周期做dirty檢查,將計算結果緩存在state里”的做法。React內核幫你維護緩存,你只需要聲明數據的計算邏輯以及數據的依賴。
  1. 函數式組件的心智模型更加“函數式”。react團隊正在循序漸進地教育社區,為未來的並發模式打下基礎。(其實react從一開始就受到了很多函數式編程的影響,現在推行函數式組件算是“回歸初心”)。下面我會詳細討論函數式組件的心智模型。

Hooks概念及常用的Hooks

Hook 是一些可以讓你在函數組件里“鈎入” React state 及生命周期等特性的函數。Hook 不能在 class 組件中使用 —— 這使得你不使用 class 也能使用 React。

React官網是這樣描述Hooks的:Hook 是 React 16.8 的新增特性。它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性。Hook 將組件中相互關聯的部分拆分成更小的函數(比如設置訂閱或請求數據),而並非強制按照生命周期划分。你還可以使用 reducer 來管理組件的內部狀態,使其更加可預測。

1. useState: State的Hook

State Hook讓函數組件也可以有state狀態, 並進行狀態數據的讀寫操作。

語法

const [xxx, setXxx] = React.useState(initValue)

useState()說明:

參數: 第一次初始化指定的值在內部作緩存;

返回值: 包含2個元素的數組, 第1個為內部當前狀態值, 第2個為更新狀態值的函數。

可以多次使用useState()

setXxx()2種寫法:

setXxx(newValue): 參數為非函數值, 直接指定新的狀態值, 內部用其覆蓋原來的狀態值

setXxx(value => newValue): 參數為函數, 接收原本的狀態值, 返回新的狀態值, 內部用其覆蓋原來的狀態值

示例

import React, { useState } from 'react';

function Example() {
  // 聲明一個叫 “count” 的 state 變量。
  const [count, setCount] = useState(0);
    
  // 加的回調 setXxx()第二種寫法
  function add() {
      setCount(count => count + 1);
  }

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me to + 1
      </button>
      <button onClick={() => setCount(add)}>
        Click me to add 1
      </button>
    </div>
  );
}

export default Example

2. useEffect: 副作用的Hook

Effect Hook 可以讓你在函數組件中執行副作用操作(用於模擬類組件中的生命周期鈎子)。

我們之前可能已經在React組件中執行過數據獲取、訂閱或者手動修改過DOM。我們統一把這些操作稱為“副作用”,或者簡稱為“作用”。它跟 class 組件中的 componentDidMountcomponentDidUpdatecomponentWillUnmount 具有相同的用途,只不過被合並成了一個 API。

React中的副作用操作

  • 發ajax請求數據獲取
  • 設置訂閱 / 啟動定時器
  • 手動更改真實DOM

語法和說明:

  • 通過使用這個 Hook,你可以告訴 React 組件需要在渲染后執行某些操作
  • useEffect 放在組件內部讓我們可以在 effect 中直接訪問 count state 變量(或其他 props)。
  • 默認情況下,它在第一次渲染之后和每次更新之后都會執行,即不加第二個參數的情況下。

總體說明:

useEffect(() => { 
	// 在此可以執行任何帶副作用操作
	return () => { // 在組件卸載前執行
	// 在此做一些收尾工作, 比如清除定時器/取消訂閱等
	}
}, [stateValue]) // 如果指定的是[], 回調函數只會在第一次render()后執行

可以多次使用useEffect

替代componentDidMount:

useEffect(() => { 
	// 在此可以執行任何帶副作用操作,來初始化代碼
}, [stateValue]) // 如果指定的是[], 回調函數只會在第一次render()后執行

替代componentDidUpdate:

useEffect(() => { 
	// 在此可以執行任何帶副作用操作
}, [stateValue]) // 如果指定的是[], 回調函數只會在第一次render()后執行,此時不能為空,數組內的值為所監控的state的值,如果不加此參數,默認為所有的state的值
// 例如如下代碼
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 僅在 count 更改時更新

替代componentWillUnmount:

useEffect(() => { 
	return () => { // 在組件卸載前執行
	// 在此做一些收尾工作, 比如清除定時器/取消訂閱等
	}
})

實例:

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>
  );
}

3. useRef: ref的Hook

Ref Hook可以在函數組件中存儲/查找組件內的標簽或任意其它數據,跟React.createRef()類似。

useRef 返回一個可變的 ref 對象,其 .current 屬性被初始化為傳入的參數(initialValue)。返回的 ref 對象在組件的整個生命周期內保持不變。

語法:

const refContainer = useRef()

ref 對象的 .current 屬性為相應的 DOM 節點。

實例:

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` 指向已掛載到 DOM 上的文本輸入元素
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

函數類組件中使用props

使用方式類似類組件的props使用,父級組件需要暴露接口給子組件,子組件才能接收,子組件接收數據的方法:直接作為函數的參數(props)傳給子組件。

import React, { useState } from 'react'
import Title from "../Title"
//父級組件傳過去
function Parent() {
    let [count, setCount] = useState(1)
    const add = (count) => { setCount(count) }
    return (<div>
        //類似類組件中的接口傳遞數據到子組件
        <Title count={count} />   
        <button onClick={() => add(count + 1)}>+</button>
    </div>)
}

export default Parent;

//子組件接收
import React from 'react'

function Title(props) {
    return (
        <h1>{props.count}</h1>
    )
}

export default Title;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM