Redux 是 React 生態(tài)系統(tǒng)中的革命性技術(shù)。它使我們能夠在全局范圍內(nèi)存儲(chǔ)不可變數(shù)據(jù),并解決了在組件樹(shù)中 prop-drilling 的問(wèn)題。需要在應(yīng)用程序之間共享不可變數(shù)據(jù)時(shí),它現(xiàn)在依舊是一種可以方便擴(kuò)展的優(yōu)秀工具。
但是,為什么我們非得需要一個(gè)全局存儲(chǔ)呢?我們的前端應(yīng)用程序真的那么復(fù)雜嗎,還是說(shuō)我們?cè)噲D用 Redux 做的事情太多了?
單頁(yè)應(yīng)用程序的問(wèn)題
React 這樣的單頁(yè)應(yīng)用程序(SPA)的出現(xiàn)為我們開(kāi)發(fā) Web 應(yīng)用程序的方式帶來(lái)了許多變化。它將我們的后端與前端代碼分離開(kāi)來(lái),使我們能夠?qū)P囊恢虏⒎蛛x出關(guān)注點(diǎn)。圍繞狀態(tài),它還引入了很多復(fù)雜性。
現(xiàn)在,異步獲取數(shù)據(jù)意味著數(shù)據(jù)必須位于兩個(gè)位置:前端和后端。我們必須考慮如何在全局范圍內(nèi)以最佳方式存儲(chǔ)這些數(shù)據(jù),以便它們能對(duì)我們的所有組件都可用,同時(shí)保持?jǐn)?shù)據(jù)緩存以減少網(wǎng)絡(luò)延遲。現(xiàn)在,前端開(kāi)發(fā)中的很大一部分負(fù)擔(dān)來(lái)自于我們的全局存儲(chǔ)的維護(hù)工作,我們還要確保這些存儲(chǔ)不會(huì)遭受狀態(tài)錯(cuò)誤、數(shù)據(jù)非規(guī)范化和陳舊數(shù)據(jù)的困擾。
Redux 不是緩存
使用 Redux 和類似的狀態(tài)管理庫(kù)時(shí),大多數(shù)人都會(huì)遇到的一大問(wèn)題是,我們會(huì)將其視為后端狀態(tài)的緩存。我們獲取數(shù)據(jù),通過(guò) reducer/action 將其添加到存儲(chǔ)中,并定期重新獲取以確保它是最新的。
我們用 Redux 做的事情太多了,甚至把它看成是解決問(wèn)題的全面解決方案。
關(guān)鍵在于,我們的前端和后端狀態(tài)永遠(yuǎn)不會(huì)真正同步,我們最多可以營(yíng)造一種它們同步的錯(cuò)覺(jué)。這是客戶端 - 服務(wù)器模型的缺點(diǎn)之一,也是為什么我們需要緩存的原因所在。但是,同步緩存和保持狀態(tài)是非常復(fù)雜的,因此我們不應(yīng)該像 Redux 鼓勵(lì)的那樣,從頭開(kāi)始重新創(chuàng)建這個(gè)后端狀態(tài)。
當(dāng)我們開(kāi)始在前端重新創(chuàng)建數(shù)據(jù)庫(kù)時(shí),后端和前端之間的職責(zé)界限很快就變得模糊不清。作為前端開(kāi)發(fā)人員,我們不需要完全了解表及其關(guān)系即可創(chuàng)建簡(jiǎn)單的 UI。
我們也不必知道如何高水平地標(biāo)準(zhǔn)化我們的數(shù)據(jù)。這種責(zé)任應(yīng)該落在設(shè)計(jì)表的那些人(后端開(kāi)發(fā)人員)身上。然后,后端開(kāi)發(fā)人員可以用文檔化的 API 形式為前端開(kāi)發(fā)人員提供抽象。
現(xiàn)在,人們圍繞 Redux 構(gòu)建了無(wú)數(shù)的庫(kù)(redux-observable、redux-saga 和 redux-thunk 等),以幫助我們管理后端數(shù)據(jù),每個(gè)庫(kù)都為已經(jīng)繁瑣不已的庫(kù)又增加了一層復(fù)雜性。我相信其中大多數(shù)都沒(méi)有達(dá)成目標(biāo)。有時(shí)為了前進(jìn)。我們需要先退后一步。
如果我們不再在前端代碼中管理后端狀態(tài),而只是將其視為需要定期更新的緩存會(huì)怎么樣呢?將前端視為從緩存讀取內(nèi)容的簡(jiǎn)單顯示層后,我們的代碼就會(huì)變得更加易用,并且更適合純前端開(kāi)發(fā)人員閱讀。我們獲得了分離關(guān)注點(diǎn)的所有好處,同時(shí)避開(kāi)了構(gòu)建 SPA 的大部分缺點(diǎn)。
后端狀態(tài)的更簡(jiǎn)單方法
我認(rèn)為有兩個(gè)庫(kù)比使用 Redux(或類似的狀態(tài)管理庫(kù))存儲(chǔ)后端狀態(tài)要好用很多。
React Query
我已經(jīng)在自己的多數(shù)個(gè)人和工作項(xiàng)目中使用 React Query 幾個(gè)月了。這個(gè)庫(kù)有一個(gè)非常簡(jiǎn)單的 API 和幾個(gè) hooks,用于管理查詢(獲取數(shù)據(jù))和突變(更改數(shù)據(jù))。
自從使用 React Query 之后,我不僅提升了效率,而且最終編寫的樣板代碼比 Redux 少了 9 成。我發(fā)現(xiàn)自己更容易將注意力集中在前端應(yīng)用程序的 UI/UX 上,不會(huì)再時(shí)刻操心整個(gè)后端狀態(tài)了。
要對(duì)比這個(gè)庫(kù)和 Redux 的話,我們來(lái)看這兩種方法的一個(gè)代碼示例。我使用常規(guī) JS、React Hooks 和 axios 實(shí)現(xiàn)了一個(gè)從服務(wù)器獲取的簡(jiǎn)單 TODO 列表。
首先是 Redux 實(shí)現(xiàn):
import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import axios from 'axios';
const SET_TODOS = "SET_TODOS";
export const rootReducer = (state = { todos: [] }, action) => {
switch (action.type) {
case SET_TODOS:
return { ...state, todos: action.payload };
default:
return state;
}
};
export const App = () => {
const todos = useSelector((state) => state.todos);
const dispatch = useDispatch();
useEffect(() => {
const fetchPosts = async () => {
const { data } = await axios.get("/api/todos");
dispatch({
type: SET_TODOS,
payload: data}
);
};
fetchPosts();
}, []);
return (
<ul>{
todos.length > 0 && todos.map((todo) =>{
<li>{todo.text}</li>
}
)
}
</ul>
);
};
請(qǐng)注意,到這里甚至還沒(méi)有開(kāi)始處理重新獲取、緩存和無(wú)效化,只是加載數(shù)據(jù)并在加載時(shí)將其存儲(chǔ)在全局存儲(chǔ)中而已。
React Query 實(shí)現(xiàn)的相同示例:
import React from "react";
import { useQuery } from "react-query";
import axios from "axios";
const fetchTodos = () => {
const { data } = axios.get("/api/todos");
return data;
};
const App = () => {
const { data } = useQuery("todos", fetchTodos);
return data ? (
<ul>{data.length > 0 && data.map((todo) => <li>{todo.text}</li>)}</ul>
) : null;
};
默認(rèn)情況下,上面的示例包括具有合理默認(rèn)值的數(shù)據(jù)重新獲取、緩存和過(guò)時(shí)內(nèi)容無(wú)效化。你可以在全局級(jí)別設(shè)置緩存配置,然后就可以忘掉它了——一般來(lái)說(shuō)它足以完成你期望的工作
現(xiàn)在,無(wú)論需要什么數(shù)據(jù),你都可以將 useQuery hook 與你設(shè)置的唯一鍵(在本例中為“todos”)一起使用,并使用異步調(diào)用來(lái)獲取數(shù)據(jù)。
要更改接口狀態(tài)時(shí),React Query 提供了 useMutation hook。
一旦你開(kāi)始使用這個(gè)庫(kù),就會(huì)發(fā)現(xiàn)在絕大多數(shù)項(xiàng)目中 Redux 都太笨重了。處理完應(yīng)用程序的數(shù)據(jù)獲取 / 緩存部分后,前端幾乎沒(méi)有全局狀態(tài)可處理??梢允褂?Context 或 useContext+useReducer 處理剩下的少量?jī)?nèi)容,代替 Redux 的作用。
或者更好的方法是,使用 React 的內(nèi)置狀態(tài)作為你的簡(jiǎn)單前端狀態(tài),這樣做肯定沒(méi)問(wèn)題的。
// clean, beautiful, and simple
const [state, setState] = useState();
我們應(yīng)該更徹底地分離后端與前端,而不是陷在這種模棱兩可的中間狀態(tài)里。本文提到的這些庫(kù)代表了我們?cè)趩雾?yè)應(yīng)用程序中管理狀態(tài)的方式變革,并且是朝著正確方向邁出的一大步。我期待著看到它們能對(duì) React 社區(qū)產(chǎn)生怎樣的影響。
文章來(lái)源:dev.to/g_abud/why-i-quit-redux-1knl
以上就是W3Cschool編程獅
關(guān)于為什么我停止使用Redux?的相關(guān)介紹了,希望對(duì)大家有所幫助。