基用React Hooks + Antd快速實現一個列表頁

忽然發現上一篇文章已是半年以前了,最近一直在沉迷工做,天天就到掘金看看漲漲姿式。可是領導最近忽然跟我說你hooks用的挺多的嘛,要不作個組內技術分享吧。因此又撿起了筆頭寫了一個相似普及Hooks的文章= =html

話說回來,如今我已經再也不使用class 組件(除非一些舊項目 或者 對function component支持度不夠,如 Taro 編寫小程序),而是全面擁抱 hooks ,統一使用函數組件,寫代碼效率提升了很多。react

根據個人實踐和對hooks的理解,它帶給我最大的感覺就是:小程序

  • 1.組件邏輯更清晰。摒棄了生命週期函數和class的一些難以理解的特性和坑,組件的渲染就是函數的執行
  • 2.提供了更好的狀態邏輯複用的途徑
  • 3.更簡潔的代碼,粒度更小的組件與邏輯

官方文檔:React Hooks中文簡介數組

下面我將會經過實現一個最多見的帶篩選項的列表頁,來跟你們分享如何使用hooks來編寫咱們的代碼,實現咱們的功能。bash

頁面原型 網絡

頁面原型
(圖片來源:阿里飛冰模板( unpkg.com/@icedesign/…))

1.使用useState初始化state


使用data和filters搭配Immutable保存列表和篩選項數據,useState函數參數爲state初始值。antd

import { fromJS } from 'immutable';
import { Table } from 'antd'; // 基礎組件基於阿里antd組件庫

function TablePage() {
    const [data, setData] = useState([]);
    const [filters, setFilters] = useState(fromJS({
        deliveryTime: [],
        orderTime: [],
        name: '',
    }));
    
    return (
        <div>
            <Filters /> {/*Filters爲具體的篩選組件,這裏略過*/}
            <Table
                dataSource={data}
            />
        </div>
    );
}

複製代碼

2.使用useEffect來執行反作用


useEffect在我看來是最重要的hooks,它給予了咱們在組件渲染後實現各類不一樣的反作用的手段。官方文檔介紹useEffect能夠看做是componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個函數的組合。因此effect在每一次渲染更新(包括第一次)後都會執行。函數

這就帶來另一個問題,如何控制useEffect的執行,因此useEffect的第二個參數這時候就發揮了做用,它提供了useEffect是否執行的依據。每次執行useEffect以前,React會判斷參數中的每一個依賴是否與上次渲染的值是否一致,若一致就會跳過執行effect,這就達到了控制的效果。post

// 當咱們想effect僅執行一次的時候,可傳入一個空數組,表示該effect不依賴於任何state或者props
useEffect(() => {
    effect1();
}, []);

// 在列表頁中,咱們須要在filters改變的時候執行獲取數據的effect,此時immutable的特性就能夠發揮出來
// 對於引用類型,每次函數執行時都至關因而一個新值,因此傳入引用類型的依賴是錯誤的,而Immutable的特性容許咱們傳入整個filters
useEffect(() => {
    getData(); // 獲取數據的函數,依賴於filters的值
}, [filters]);

複製代碼

因此咱們如今的頁面代碼看起來就像這樣:fetch

function TablePage() {
    const [data, setData] = useState([]);
    const [filters, setFilters] = useState(fromJS({
        deliveryTime: '',
        orderTime: '',
        name: '',
    }));
    
    useEffect(() => {
        getData(); // 獲取數據的函數,依賴於filters的值
    }, [filters]);
    
    function getData() { // 一個經過網絡請求獲取數據的函數
        fetchAPI({
            deliveryTime: filters.get('deliveryTime'),
            orderTime: filters.get('orderTime'),
            name: filters.get('name'),
        })
            .then((rsp) => {
                setData(rsp.data);
            });
    }
    
    function handleFiltersChange(key, value) {
        setFilters(filters.set(key, value);
    }
    
    return (
        <div>
            <Filters onChange={handleFiltersChange} /> {/*Filters爲具體的篩選組件,這裏略過*/}
            <Table
                dataSource={data}
            />
        </div>
    );
}

複製代碼

3.自定義Hooks實現邏輯複用


在平常開發中,咱們會有不少不少的邏輯實際上是重複的,當咱們想在兩個函數之間共享邏輯時,咱們會把它提取到第三個函數中。而組件和 Hook 都是函數,因此也一樣適用這種方式。這第三個函數就是咱們的自定義Hook。
自定義 Hook 是一個函數,其名稱以 「use」 開頭且必須以 「use」 開頭;函數內部能夠調用其餘的 Hook,且其內部的Hook是徹底獨立的。

3.1 usePagination實現分頁邏輯

function usePagination(paginationOptions) {
  const [_pagination, setPagination] = useState(fromJS({
    total: 0,
    current: 1,
    pageSize: 10,
    ...paginationOptions,
  }));

  return [_pagination, setPagination];
}
複製代碼

3.2 useDebounce實現請求接口防抖

function useDebounce() {
  const [timer, setTimer] = useState(0);

  function debounce(throttleFunc, ThrottleTime = 250) {
    clearTimeout(timer);
    setTimer(setTimeout(throttleFunc, ThrottleTime));
  }

  return debounce;
}
複製代碼

這時列表頁面中能夠像以下這樣使用咱們的自定義hooks:

function TablePage() {
    const [data, setData] = useState([]);
    const [filters, setFilters] = useState(fromJS({
        deliveryTime: '',
        orderTime: '',
        name: '',
    }));
    const [pagination, setPaination] = usePagination();
    const debounce = useDebounce(); // 獲取debounce函數
    
    useEffect(() => {
        debounce(getData); // 獲取數據的函數,依賴於filters的值
    }, [filters]);
    
    function getData() { // 一個經過網絡請求獲取數據的函數
        fetchAPI({
            deliveryTime: filters.get('deliveryTime'),
            orderTime: filters.get('orderTime'),
            name: filters.get('name'),
        })
            .then((rsp) => {
                setData(rsp.data);
            });
    }
    
    function handleFiltersChange(key, value) {
        setFilters(filters.set(key, value);
    }
    
    function handleTableChange(_pagination) {
        setPaination(
            pagination.set('current', _pagination.current)
                .set('pageSize', _pagination.pageSize)
        );
    }
    
    return (
        <div>
            <Filters onChange={handleFiltersChange} /> {/*Filters爲具體的篩選組件,這裏略過*/}
            <Table
                columns={/* wirte your own columns config */}
                dataSource={data}
                onChange={handleTableChange}
            />
        </div>
    );
複製代碼

想了解更多自定義hooks的玩法,能夠了解一下如下文章:
2019年了,整理了N個實用案例幫你快速遷移到React Hooks
React hooks 的嘗試使用 (個人關於hooks的上一篇文章,包括useContext合useReducer的一些使用和一些自定義hooks)

4.總結


這樣咱們基本上就實現了一個用Hooks管理的函數組件了,可能這一個簡單的案列還不能徹底體現hooks的優點,還有一些優化手段諸如useMemo和useCallback搭配HOC,還有最近在使用的TypeScript,這些咱們之後有機會再講。最後歡迎你們給我提意見,多交流,讓咱們在掘金共同進步!

相關文章
相關標籤/搜索