前言
這是一篇比較全面講解 React 的文章,裡面很多基礎知識希望你自己一邊查閱資料一邊學習。全文從業務開發中最常用見 loading 效果不同是實現講起,說下現在前端開發在業務上應該有的思考。
入門級操作
State
最簡單的實現,我們在 Loading 元件內部宣告一個狀態,通過程式碼邏輯判斷 loading 效果的展示。
export default class extends Component {
...
render() {
return this.state.loading ? <div className="loader" /> : <div>finish</div>;
}
}
複製程式碼
Props
隨著業務的發展,這個 Loading 元件用到的地方會非常多,上面這個程式碼耦合了很多邏輯,為了讓這個元件能夠很好的複用,那我們抽離出元件的業務邏輯,將內部狀態進行提升,那這個元件就是一個能被複用的 UI 元件。
export default function(props) {
return props.loading ? <div className="loader" /> : <div>finish</div>;
}
複製程式碼
注:上面兩段程式碼你可能會想,為什麼 Func
和 Class
都能實現一個元件,他們有什麼差別嗎?
其實你在開發時不容易感覺到差別,但 React 本身是進行了很多差別處理,如果是 Class 類,React 會用 new
關鍵字例項化,然後呼叫該例項的 render
方法,如果是 Func 函式,React 會直接呼叫它。
Refs
如果你是一個 jQuery 轉型 React 的開發,會很自然的想到,我找到 Loading 元件的節點,控制他的顯示與隱藏,當然這也是可以的,React 提供 Refs 方便你訪問 DOM 節點 或 React 元素。
export default class extends Component {
componentDidMount() {
fetch().then(() => {
this.el.changeLoading(false);
});
}
render() {
return (
<Loading ref={el => { this.el = el; }} />
);
}
}
複製程式碼
通用邏輯抽離
當你的應用做到一定的複雜度,不同的頁面都會有 loading 效果,你肯定不希望每個頁面都重複的書寫一樣的邏輯,這樣會導致你的程式碼重複且混亂。
React 中有兩個比較常見的解決方案 HOC
和 Render Props
,其實這兩個這兩個概念都是不依賴 React 的。
讓我們暫時忘掉 React,下面我對 HOC
和 Render Props
寫兩個例子,你會發現元件複用是如此簡單。
HOC
HOC 其實就是一種裝飾器模式,它接受一個元件作為引數,然後返回相同的元件,這樣就可以額外增加一些功能。
const func = () => {
console.log("func");
};
const wrap = func => {
console.log("wrap");
return func;
};
// wrap 邏輯已被複用
wrap(func)();
複製程式碼
Render Props
Render Props 就是我們給一個函式傳遞一個回撥函式做為引數,該回撥函式就能利用外面函式的執行結果做為引數,執行任何操作。
const func = param => {
console.log("func");
};
const wrap = (param, func) => {
console.log("wrap");
func(param);
};
// wrap 邏輯已被複用
wrap("", func);
複製程式碼
相同點:
- 兩者都能很好的幫助我們
重用元件邏輯
; - 和回撥函式類似,當巢狀層數很多時,會造成
回撥地獄
。
不同點:
- HOC 和 父元件有相同屬性名屬性傳遞過來,會造成屬性丟失;
- Render Props 你只需要例項化一箇中間類,而 HOC 你每次呼叫的地方都需要額外例項化一箇中間類。
總的來說,在需要複用元件邏輯的時候,我個人更傾向於 Render Props 的方式。
複雜狀態管理
當你的應用越來越大,元件之間互動越來越複雜,那整個頁面的資料邏輯將變得難以管理,這時候為了方便管理應用的狀態,你可以選擇一些狀態管理工具,例如 Redux、Flux、dva 等。
Redux

我不太想談這些資料流框架,因為他們的概念 action
、store
、dispatch
太過於生澀難懂。
現代前端框架 React 和 Vue 其實都是一個套路,通過資料渲染試圖,然後檢視上操作反過來更新資料,重新渲染檢視,重新整理頁面。
資料叫做 store
,動作叫做 ation
,觸發行為叫 dispatch
,然後資料到檢視的渲染由 React/Vue 處理的。
(圖片來自 這裡)
// reducers.js
const initialState = {
loading: false
};
export default function reducer(state = initialState, action) {
switch (action.type) {
case "CHANGE_LOADING":
return {
loading: action.payload
};
default:
return state;
}
}
複製程式碼
Saga
當你程式碼中有大量的非同步操作時,例如 fetch 請求,你肯定會想到事件監聽
、回撥函式
、釋出/訂閱
。
很好,上一個例子其實就是事件監聽
的處理方式,然後回撥函式
的主流的解決方案是 redux-thunk,而釋出/訂閱
的主流解決方案是 saga。
import { takeLatest, put } from "redux-saga/effects";
import fetch from "./fetch";
function* fetchInfo(action) {
yield put({
type: "CHANGE_LOADING",
payload: true
});
yield fetch();
yield put({
type: "CHANGE_LOADING",
payload: false
});
}
export default function* fetchSaga() {
yield takeLatest("FETCH_REQUEST", fetchInfo);
}
複製程式碼
當你耐心看到這裡,我知道你對 React 肯定有一定的經驗,現在還可以做很多,例如把 loading 狀態提升到 Store 的頂部,那整個站點就只有一個 loading 了,然後你還可以將 fetch 再封裝一個 HOC 修改 loading 狀態,這就是一個相對完美的 loading,其實 React 業務開發都可以用這個套路。
新的 API
Context

上面 redux 的例子是不是過於複雜 對於簡單的業務,雖然有很多頁面,巢狀層次也很複雜,你當然可以不用狀態管理工具,你可以試著使用 Context,它可以方便你傳遞資料,它其實就是 Render Props 的一種實現。
export default React.createContext({
loading: false,
changeLoading: () => {}
});
複製程式碼
Hooks
寫到這,靜一下,是不是哪裡做錯了什麼?
我的業務只是想寫個簡單的 loading 效果,卻瞭解了一堆元件生命週期的概念。
Hooks 剛好幫你解決了這樣的問題,Hooks 能允許你通過執行單個函式呼叫來使用函式中的 React 功能,讓你把面向生命週期程式設計
變成面向業務邏輯程式設計
。
import React, { useState, useEffect } from "react";
import Loading from "./Loading/index";
import fetch from "./fetch";
function App() {
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch().then(() => {
setLoading(false);
});
}, []);
return <Loading loading={loading} />;
}
export default App;
複製程式碼
好好總結
上面對每個點都做了具體實現,但他們都不是隔離的,你可以根據你的認知和業務特點總結抽象一套自己的方法論;
多瞭解
、多抽象
、多思考
,練就十八般武藝,遇到問題的時候才能遊刃有餘;
React 現在宣傳的東西越來越多,你最好先深入瞭解他們,然後用批判的眼光,保持理智,防止自己每天用很新的特性重構你自己的程式碼。
參考文章
When do I know I’m ready for Redux?
文章可隨意轉載,但請保留此 原文連結。
非常歡迎有激情的你加入 ES2049 Studio,簡歷請傳送至 caijun.hcj(at)alibaba-inc.com 。