2020 年 React 狀態管理

xiaoT發表於2020-04-06

原文地址: medium.com/better-prog…
譯文地址:github.com/xiao-T/note…
本文版權歸原作者所有,翻譯僅用於學習。


我們是否還需要 Redux 和 Mobx 這類的狀態管理框架?

2020 年 React 狀態管理

引言

React hooks 的引入無疑改變的了 state 管理的現狀。

在此之前,很難在元件之間共享 state 相關的邏輯。現在,我們可以很簡單的通過抽象一個 hook 來處理(例如:useUserLogin)。

這就引出了問題,為什麼我們還需要狀態管理框架?在這篇文章中,我將展示我的決策過程:如何管理 state。關於在2020年我們是否還需要 state 管理框架,我也會分享我的觀點。

有什麼變化?

在有 Hooks 之前,我們是如何定義 state 的?基本上,有兩種選擇:在元件內部定義本地 state,或者用一個 state 管理框架設定全域性的 state (例如:Mobx/Redux)。

本地 state (hooks 之前)

export class UserList extends Component {
    state = {
        isLoading: false,
        hasError: false,
        users: []
    }

    searchUsers(value) {
        this.setState({isLoading: true});

        api.get(`/users?searchKey=${value}`)
            .then((data) => this.setState({users: data}))
            .catch(() => this.setState({hasError: true}))
            .finally(() => this.setState({loading: false}));
    }

    render() {
        if (this.state.isLoading) {
            // render loading spinner
        }
        
        if (this.state.hasError) {
            // render error message
        }

        return (
            <div>
                <input onChange={(event) => this.searchUsers(event.target.value)} />
            </div>
        )
       
    }
}
複製程式碼

在接下來我們會說明只有這兩個選擇時帶來的問題。假設,我們的 state 不必設為全域性,但是,我們希望可以在多個元件複用 state,我們該如何定義本地 state。

在上面的演示中,我們或許想複用 loading 和 error state,在 Hooks 之前,是不可能的。唯一的選擇是需要利用 Redux 來複用它。在 Redux 中,任何需要搜尋使用者的元件只需簡單 dispatch 一個 action(searchUsers())和監聽全域性 state 的變化即可。

然而,使用這些全域性 state(Redux/Mobx)會帶來一些問題:

  • 更多的樣板程式碼
  • 複雜的資料流
  • 多個元件同時維護全域性 state,這可以能會帶來意想不到的副作用。

解決方案:React Hooks!

謝天謝地 React v16.8 引入的 Hooks。從這時起,在做元件之間共享 state 相關的邏輯變得可行。

在下面的演示中,我們可以共享 loading 和 error 的行為:

import {useState} from 'react';

const useRequestHandler = () => {
    const [isLoading, setLoading] = useState(false);
    const [hasError, setError] = useState(false);
    const [data, setData] = useState(null);

    const handleRequest = (request) => {
        setLoading(true);
        setError(false);

        return api.get(request)
            .then(setData)
            .catch(() => setError(true))
            .finally(() => setLoading(false))
    };

    return {isLoading, hasError, data, handleRequest};
};


const UserList = () => {
    const {data, isLoading, hasError, handleRequest} = useRequestHandler();
    
    const searchUsers = (value) => handleRequest(`/users?searchKey=${value}`);
  
    return (
        <React.Fragment>
            {data.map(u => <p>{u.name}</p>)}
        </React.Fragment>
    )
}
複製程式碼

更多好處:如果,多個元件需要搜尋使用者列表的功能,我們也可以自定義 useUserSearch hook。

然而,hooks 並不是銀彈。把 state 儲存在 hook 中,並不意味著它就變成了單例物件,它只是繫結在一個元件中。在某些情況下,我們只想保留一個例項 state 物件(例如:只載入一次使用者資訊)。這是 state 管理框架提供的功能。

如何,何時,何地管理 state

現在,可以在多個元件之間共享 state 相關邏輯了,那我們怎麼決定 state 儲存在元件內(本地),還是儲存在 state 管理框架中(全域性)呢?

下面的圖片展示了我的決策過程。

2020 年 React 狀態管理

State 管理框架有什麼好處呢?

現在,我們知道如何在全域性和本地做抉擇了。但是,在2020年為什麼還需要 state 管理框架呢?這相比 React Hooks 有什麼好處呢?

有以下幾個好處:

  • 全域性定義,也代表只有一個例項物件
  • 只會載入一次遠端資料
  • 開發工具的支援
  • 為軟體工程師提供了一種標準的開發方式

總結

我們看到 React Hooks 已經攪動了 state 管理的格局。由於它們的引入,在元件之間共享 state 相關邏輯變得更加簡單。

然而,Hooks 並不是銀彈,我們仍舊需要 state 管理框架。這也並不是說要讓所有的 state 都是全域性的 — 大多情況下讓其保留在元件之間更加好。只有在有絕對必要的情況下,才把 state 移動到 state 管理框架中。

相關文章