高級前端開發工程師必備:Hooks、React Router v6 和狀態管理
點擊下方“前端開發博客”,關注并“設為星標”
大家好,我是漫步
最近一個大佬的簡歷這樣子寫的,“可以熟練利用react全家桶進行開發。對ahooks部分源碼閱讀,加深對hooks的基本使用及其內部的實現原理有了深層次的理解;閱讀過react-rouer v6的源碼,進行過技術分享;對技術選型( redux、dva/core、 mobx )有著一-定的認知和使用。”,本文試著講解這些內容。
作為一名高級前端開發工程師,我們需要深入理解 Hooks 的原理和使用方法,才能更好地利用 Hooks 來開發高質量的 React 應用。
在本篇文章中,我們將通過 ahooks 源碼閱讀,深入理解 Hooks 的原理。同時,我們也將探索 React Router v6 的新特性,并對 Redux、Dva/Core 和 Mobx 這三種狀態管理方案進行比較和實踐。
2.深入理解 Hooks
ahooks 是一個第三方 React Hook 庫,它提供了許多常用的 Hook,可以幫助開發者快速構建 React 應用程序。ahooks 的源碼位于 GitHub 上,可以通過以下鏈接訪問:
ahooks 的源碼采用 TypeScript 編寫,結構清晰、易于理解。ahooks 的核心是 useHook() 函數,它用于注冊和調用 Hook。
useHook() 函數的參數是一個對象,對象的鍵是 Hook 的名稱,值是 Hook 的實現。例如,以下代碼用于注冊 useState() Hook:
import { useHook } from "ahooks";
const useState = useHook("useState");
注冊 Hook 后,就可以在組件中使用了。例如,以下代碼用于使用 useState() Hook 獲取和更新組件的狀態:
function App() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
hooks 的基本使用
hooks 的基本使用非常簡單,只需要遵循以下步驟:
-
導入 Hook。
-
注冊 Hook。
-
在組件中使用 Hook。
例如,以下代碼用于使用 useState() Hook 獲取和更新組件的狀態:
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
hooks 的內部實現原理
hooks 的內部實現原理是基于 React 的 Hook API。React 的 Hook API 允許開發者在函數組件中使用狀態和副作用。
hooks 的核心是 useHook() 函數,它用于注冊和調用 Hook。useHook() 函數會將 Hook 的實現轉換為一個 React 函數。
例如,以下代碼用于注冊 useState() Hook:
import { useHook } from "ahooks";
const useState = useHook("useState");
// useHook() 函數會將 useState() Hook 的實現轉換為以下 React 函數:
JavaScript
function useState(initialState) {
const [state, setState] = React.useState(initialState);
return [state, setState];
}
因此,在組件中使用 useState() Hook 時,實際上是調用了 useState() Hook 的實現。
ahooks 的優勢
ahooks 具有以下優勢:
-
豐富的 Hook 庫。 ahooks 提供了許多常用的 Hook,可以幫助開發者快速構建 React 應用程序。
-
靈活的 Hook 實現。 ahooks 的 Hook 實現非常靈活,可以滿足各種需求。
-
高質量的 Hook。 ahooks 的 Hook 經過了嚴格的測試,確保了穩定性和性能。
2.1 useState:狀態管理的基礎
useState 是 Hooks 中最基礎的 Hook,它用于管理組件的狀態。useState 的返回值是一個數組,第一個元素是當前狀態的值,第二個元素是一個函數,用于更新狀態。
const [count, setCount] = useState(0);
function App() {
return (
<div>
<button onClick={() => setCount(count + 1)}>
count: {count}
</button>
</div>
);
}
在上述代碼中,我們使用 useState 來管理一個計數器的狀態。count 是當前狀態的值,setCount 是用于更新狀態的函數。
2.2 useEffect:處理副作用和生命周期
useEffect 是 Hooks 中用于處理副作用的 Hook。useEffect 的第一個參數是副作用函數,第二個參數是一個可選的依賴數組,用于控制副作用函數何時執行。
useEffect(() => {
// 副作用函數
}, []);
在上述代碼中,我們使用 useEffect 來執行一個副作用函數,該函數用于初始化計數器的狀態。
2.3 useRequest:自定義 Hook 的實現原理
useRequest 是一個自定義 Hook,它用于發送 HTTP 請求。useRequest 的第一個參數是請求的 URL,第二個參數是請求的方法,第三個參數是請求的參數,第四個參數是一個可選的回調函數,用于處理請求成功或失敗后的回調。
const useRequest = (url, method, params, onSuccess, onError) => {
// 自定義 Hook 的實現邏輯
};
在上述代碼中,我們定義了一個 useRequest 自定義 Hook。該 Hook 用于發送 HTTP 請求。
userEffect與useRequest區別
useEffect 和 useRequest 都是 React 的 Hook,用于處理副作用。但是,它們之間有一些關鍵的區別。
useEffect 是通用的 Hook,可以用于處理任何類型的副作用,包括 HTTP 請求。useRequest 是專門用于發送 HTTP 請求的 Hook。
useEffect 的回調函數會在組件初始渲染完成后,以及組件的狀態或 props 發生變化時執行。useRequest 的回調函數只會在組件初始渲染完成后執行一次。
useEffect 的回調函數可以接收多個依賴項。useRequest 的回調函數只能接收一個依賴項,即 HTTP 請求的 URL。
useEffect 的回調函數可以返回一個函數,用于清理副作用。useRequest 的回調函數不需要返回任何值。
以下是 useEffect 和 useRequest 的使用示例:
// useEffect
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
// 每當 count 發生變化時,都會執行此回調函數。
setInterval(() => {
setCount(count + 1);
}, 1000);
}, [count]);
return (
<div>
<h1>Count: {count}</h1>
</div>
);
}
// useRequest
function App() {
const [data, setData] = useState(null);
useRequest("/api/data", (response) => {
// 只會在組件初始渲染完成后執行一次。
setData(response.data);
});
return (
{data &&
Data: {data.name}
}{!data &&
Loading...
});
}
在第一段示例中,useEffect 用于每隔一秒鐘增加 count 的值。在第二段示例中,useRequest 用于在組件初始渲染完成后,發送 HTTP 請求并獲取數據。
在實際開發中,我們應該根據具體的需求選擇合適的 Hook。如果需要處理復雜的副作用,useEffect 是一個更好的選擇。如果只需要發送簡單的 HTTP 請求,useRequest 是一個更好的選擇。
React hook 18改進
---------------
截至2023年8月3日,React Hook的最新版本是18。React Hook 18 于 2022 年 10 月 27 日發布。
React Hook 18 引入了許多新特性和改進,包括:
* Concurrent Mode:支持并發模式,可以讓 React 應用程序更高效地利用多核 CPU。
* Suspense:可以暫停渲染組件,直到數據加載完成。
* Incremental Static Regeneration:可以生成靜態 HTML,提高應用程序的性能。
### Concurrent Mode
* useTransition():用于在并發模式下處理狀態變化。
* useDeferredValue():用于在并發模式下延遲渲染組件。
Concurrent Mode 是 React 18 的核心特性之一。它允許 React 應用程序在同一時間渲染多個組件,從而提高應用程序的性能。
Concurrent Mode 有以下幾個優勢:
* 提高應用程序的性能:Concurrent Mode 可以讓 React 應用程序在同一時間渲染多個組件,從而減少 CPU 的占用。
* 改善應用程序的用戶體驗:Concurrent Mode 可以讓應用程序更流暢地響應用戶的操作。
* 簡化開發:Concurrent Mode 可以讓開發者更輕松地編寫并發的 React 應用程序。
// Concurrent Mode
function App() {
const [count, setCount] = useState(0);
useTransition({
// 在并發模式下,狀態變化會立即觸發組件的重渲染,但不會立即更新 DOM。
// 需要使用 useTransition 鉤子來確定何時更新 DOM。
onEnter: () => {
// 在組件進入并發模式時執行。
setCount(count + 1);
},
onLeave: () => {
// 在組件離開并發模式時執行。
},
});
return (
Count: {count}
);
}
### Suspense
* `Suspense`:用于暫停渲染組件,直到數據加載完成。
* `<Suspense fallback={...}>`:用于指定暫停渲染時顯示的默認內容。
Suspense 是 React 18 引入的另一個重要特性。它允許 React 應用程序暫停渲染組件,直到數據加載完成。
Suspense 有以下幾個優勢:
* 提高應用程序的性能:Suspense 可以讓 React 應用程序在數據沒有加載完成之前,不渲染依賴該數據的組件,從而減少 CPU 的占用。
* 改善應用程序的用戶體驗:Suspense 可以讓應用程序在數據沒有加載完成之前,顯示一個默認的占位符,從而避免用戶看到空白的屏幕。
* 簡化開發:Suspense 可以讓開發者更輕松地處理異步數據的加載。
// Suspense
function App() {
const [data, setData] = useState(null);
useEffect(() => {
// 異步加載數據。
// 在數據加載完成之前,組件將暫停渲染。
fetch("/api/data").then((res) => {
setData(res.json());
});
}, []);
return (
{data &&
Data: {data.name}
}{!data && <Suspense fallback={
Loading...
}>Loading...
}
);
}
### Incremental Static Regeneration
* `useStaticQuery()`:用于在靜態 HTML 中獲取數據。
* `<StaticQuery query={...}>`:用于在靜態 HTML 中渲染組件。
Incremental Static Regeneration 是 React 18 引入的第三個重要特性。它允許 React 應用程序生成靜態 HTML,從而提高應用程序的性能。
Incremental Static Regeneration 有以下幾個優勢:
* 提高應用程序的性能:Incremental Static Regeneration 可以讓 React 應用程序在首次加載時生成靜態 HTML,從而減少瀏覽器在運行時渲染的 DOM 的數量。
* 改善應用程序的 SEO:Incremental Static Regeneration 可以讓 React 應用程序的靜態 HTML 被搜索引擎索引,從而改善應用程序的 SEO 效果。
* 簡化開發:Incremental Static Regeneration 可以讓開發者更輕松地生成靜態 HTML。
// Incremental Static Regeneration
function App() {
const [data, setData] = useState([]);
useEffect(() => {
// 異步加載數據。
fetch("/api/data").then((res) => {
setData(res.json());
});
}, []);
return (
{data.map((item) => (
))}
);
}
除了以上三個重要特性之外,React Hook 18 還引入了許多其他新特性和改進,包括:
對 useState()、useEffect() 和 useContext() 等 Hook 進行了改進,使其更靈活、更易用。新增了 useDeferredValue() Hook,用于在并發模式下延遲渲染組件。新增了 useStaticQuery() 和組件,用于在靜態 HTML 中獲取數據和渲染組件。
總體而言,React Hook 18 是一個重大更新,引入了許多新特性和改進,可以讓 React 應用程序更高效、更流暢、更易用。
探索 React Router v6
------------------
React Router v6 是 React Router 的最新版本,它基于 React Hooks 重構,提供了更簡潔的 API 和更強大的功能。
在 React Router v6 中,路由匹配和導航轉換器是兩個重要的概念。路由匹配用于確定當前路徑匹配哪個路由,導航轉換器用于將路由匹配結果轉換為 React 元素。
### 路由匹配
路由匹配是 React Router v6 的基礎。路由匹配使用路徑正則表達式來匹配當前路徑。
const routes = [
{
path: "/",
component: Home,
},
{
path: "/about",
component: About,
},
];
const App = () => {
return (
{routes.map((route, index) => (
))}
);
};
在上述代碼中,我們定義了兩個路由。第一個路由的路徑是 `/`,第二個路由的路徑是 `/about`。
當用戶訪問 `http://localhost:3000` 時,React Router 會使用 `/` 路由的路徑正則表達式來匹配當前路徑。由于 `http://localhost:3000` 與 `/` 路徑匹配,因此 React Router 會渲染 `Home` 組件。
當用戶訪問 `http://localhost:3000/about` 時,React Router 會使用 `/about` 路徑正則表達式來匹配當前路徑。由于 `http://localhost:3000/about` 與 `/about` 路徑匹配,因此 React Router 會渲染 `About` 組件。
### 導航轉換器
導航轉換器用于將路由匹配結果轉換為 React 元素。React Router v6 提供了多種內置的導航轉換器,例如 `Route`、`Redirect` 和 `Switch`。
const routes = [
{
path: "/",
component: Home,
},
{
path: "/about",
component: About,
},
];
const App = () => {
return (
{routes.map((route, index) => (
))}
);
};
在上述代碼中,我們使用 `Route` 導航轉換器來渲染路由匹配結果。
### 共享路由狀態:React Context 的應用
React Router v6 支持使用 React Context 來共享路由狀態。
const App = () => {
const [location, setLocation] = useState({
pathname: "/",
});
return (
{routes.map((route, index) => (
))}
);
};
在上述代碼中,我們使用 React Context 來存儲路由的 `location` 屬性。
`location` 屬性包含了路由的當前路徑、查詢參數和哈希。我們可以使用 `location` 屬性來獲取路由的當前狀態。
技術選型與使用
-------
Redux、Dva/Core 和 Mobx的比較與實踐
React 的狀態管理是開發中的重要問題。React 提供了 `useState` 和 `useReducer` 等 Hooks 來處理狀態管理,但是這些 Hooks 只能處理簡單的狀態管理需求。
對于復雜的狀態管理需求,我們需要使用第三方狀態管理庫,例如 Redux、Dva/Core 和 Mobx。
### Redux
Redux 是 React 最流行的狀態管理庫。Redux 采用單一狀態樹的設計,將所有狀態集中在一個單一的 store 對象中。
#### Redux 的優點在于:
* 可預測性:Redux 的狀態變化是通過 action 和 reducer 來實現的,這使得狀態變化非常可預測。
* 可測試性:Redux 的狀態變化是通過函數來實現的,這使得狀態變化非常容易測試。
* 可擴展性:Redux 采用了模塊化設計,可以很容易地擴展。
#### Redux 的缺點在于:
* 學習曲線較高:Redux 的概念比較抽象,學習曲線較高。
* 性能:Redux 的狀態樹是全局的,這會導致性能問題。
**實現了一個簡單的計數器功能,以下三個代碼都是同樣功能**
下面這個示例代碼使用了 `createStore` 方法創建了 `store` 對象,并使用 `combineReducers` 方法將 `count` 狀態合并到 `store` 中。
import React, { useState } from "react";
import { createStore, combineReducers } from "redux";
const initialState = {
count: 0,
};
const reducers = combineReducers({
count: (state = initialState.count, action) => {
switch (action.type) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
default:
return state;
}
},
});
const store = createStore(reducers);
function App() {
const [count, setCount] = useState(store.getState().count);
const increment = () => {
store.dispatch({ type: "increment" });
};
const decrement = () => {
store.dispatch({ type: "decrement" });
};
return (
);
}
export default App;
Dva/Core
--------
Dva/Core 是另一個流行的 React 狀態管理庫。Dva/Core 采用了類似 Redux 的單一狀態樹的設計,但是 Dva/Core 使用了更簡單的語法。
#### Dva/Core 的優點在于:
* 學習曲線較低:Dva/Core 的語法更簡單,學習曲線較低。
* 性能:Dva/Core 的狀態樹是局部的,這可以提高性能。
#### Dva/Core 的缺點在于:
* 可預測性:Dva/Core 的狀態變化是通過函數來實現的,這使得狀態變化的預測性略差于 Redux。
* 可測試性:Dva/Core 的狀態變化是通過函數來實現的,這使得狀態變化的測試性略差于 Redux。
以下示例代碼使用了 `useDvaStore` 方法獲取 `store` 對象,并使用 `store.state` 屬性獲取 `count` 狀態。
import React from "react";
import { useDvaStore } from "dva/core";
const initialState = {
count: 0,
};
const reducers = {
count: (state = initialState.count, action) => {
switch (action.type) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
default:
return state;
}
},
};
const store = useDvaStore(reducers);
function App() {
const [count, setCount] = useState(store.state.count);
const increment = () => {
store.dispatch({ type: "increment" });
};
const decrement = () => {
store.dispatch({ type: "decrement" });
};
return (
count: {count}
);
}
export default App;
### Mobx
Mobx 是 React 的另一個狀態管理庫。Mobx 采用了響應式編程的設計,可以自動更新 UI 狀態。
#### Mobx 的優點在于:
* 易用性:Mobx 的語法非常簡單,易于上手。
* 性能:Mobx 采用了響應式編程的設計,可以提高性能。
#### Mobx 的缺點在于:
* 可預測性:Mobx 的狀態變化是通過響應式編程來實現的,這使得狀態變化的預測性略差于 Redux。
* 可測試性:Mobx 的狀態變化是通過響應式編程來實現的,這使得狀態變化的測試性略差于 Redux。
以下示例代碼使用了 `observable` 方法將 `count` 狀態轉換為可觀察的狀態
import React from "react";
import { observable } from "mobx";
const initialState = {
count: 0,
};
const count = observable(initialState.count);
function App() {
const increment = () => {
count.value += 1;
};
const decrement = () => {
count.value -= 1;
};
return (
count: {count}
);
}
export default App;
總結
--
Redux、Dva/Core 和 Mobx 都是功能強大的 React 狀態管理庫。我們可以根據自己的實際需求來選擇合適的狀態管理庫。
對于復雜的狀態管理需求,Redux 是一個不錯的選擇。Redux 的單一狀態樹設計可以確保狀態的一致性和可預測性,同時 Redux 的模塊化設計也使得狀態管理更加靈活。
對于簡單的狀態管理需求,Dva/Core 和 Mobx 是更好的選擇。Dva/Core 的學習曲線較低,Mobx 的易用性較高。
當然,我們也可以根據自己的實際需求,將不同的狀態管理庫組合使用。例如,我們可以使用 Redux 來管理全局狀態,使用 Dva/Core 來管理局部狀態。
**福利**
我給讀到文末的讀者準備了一個福利,在前端開發博客公眾號后臺回復“React 核心”,下載本文的高清思維腦圖。
關注我
---
如果喜歡我的分享,點擊下方關注,文末點一個贊 ?? ?分享 是對我最大的支持
我的微信公眾號:前端開發博客,在后臺回復以下關鍵字可以獲取資源。
* 回復「小抄」,領取Vue、JavaScript 和 WebComponent 小抄 PDF
* 回復「Vue腦圖」獲取 Vue 相關腦圖
* 回復「思維圖」獲取 JavaScript 相關思維圖
* 回復「簡歷」獲取簡歷制作建議
* 回復「簡歷模板」獲取精選的簡歷模板
* 回復「加群」進入500人前端精英群
* 回復「電子書」下載我整理的大量前端資源,含面試、Vue實戰項目、CSS和JavaScript電子書等。
* 回復「知識點」下載高清JavaScript知識點圖譜

浙公網安備 33010602011771號