這是一篇比較全面講解 React 的文章,裏面不少基礎知識但願你本身一邊查閱資料一邊學習。全文從業務開發中最經常使用見 loading 效果不一樣是實現講起,說下如今前端開發在業務上應該有的思考。前端
入門級操做react
State編程
最簡單的實現,咱們在 Loading 組件內部聲明一個狀態,經過代碼邏輯判斷 loading 效果的展現。redux
export default class extends Component {
...
render() {
return this.state.loading ? :
finish
;
}
}
複製代碼
隨着業務的發展,這個 Loading 組件用到的地方會很是多,上面這個代碼耦合了不少邏輯,爲了讓這個組件可以很好的複用,那咱們抽離出組件的業務邏輯,將內部狀態進行提高,那這個組件就是一個能被複用的 UI 組件。bash
export default function(props) {
return props.loading ? :
finish
;
}
複製代碼
注:上面兩段代碼你可能會想,爲何 Func 和 Class 都能實現一個組件,他們有什麼差異嗎? 其實你在開發時不容易感受到差異,但 React 自己是進行了不少差異處理,若是是 Class 類,React 會用 new 關鍵字實例化,而後調用該實例的 render 方法,若是是 Func 函數,React 會直接調用它。前端框架
若是你是一個 jQuery 轉型 React 的開發,會很天然的想到,我找到 Loading 組件的節點,控制他的顯示與隱藏,固然這也是能夠的,React 提供 Refs 方便你訪問 DOM 節點 或 React 元素。框架
export default class extends Component {
componentDidMount() {
fetch().then(() => {
this.el.changeLoading(false);
});
}
render() {
return (
{ 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 就是咱們給一個函數傳遞一個回調函數作爲參數,該回調函數就能利用外面函數的執行結果作爲參數,執行任何操做。
const func = param => {
console.log("func");
};
const wrap = (param, func) => {
console.log("wrap");
func(param);
};
// wrap 邏輯已被複用
wrap("", func);
複製代碼
相同點:
不一樣點:
複雜狀態管理
當你的應用愈來愈大,組件之間交互愈來愈複雜,那整個頁面的數據邏輯將變得難以管理,這時候爲了方便管理應用的狀態,你能夠選擇一些狀態管理工具,例如 Redux、Flux、dva 等。
// 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;
}
}
複製代碼
當你代碼中有大量的異步操做時,例如 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
export default React.createContext({
loading: false,
changeLoading: () => {}
});
複製代碼
寫到這,靜一下,是否是哪裏作錯了什麼? 個人業務只是想寫個簡單的 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 ;
}
export default App;
複製代碼
好好總結
上面對每一個點都作了具體實現,但他們都不是隔離的,你能夠根據你的認知和業務特色總結抽象一套本身的方法論; 多瞭解、多抽象、多思考,練就十八般武藝,遇到問題的時候才能遊刃有餘; React 如今宣傳的東西愈來愈多,你最好先深刻了解他們,而後用批判的眼光,保持理智,防止本身天天用很新的特性重構你本身的代碼。