React 導讀(一)
React 導讀(二)javascript
在以前 2 篇文章中中學習到了寫第一個 Web 組件以及經常使用的生命週期函數的使用,這篇文章將繼續以前的目錄,開始新的知識點補充:css
這篇文章主要會介紹第六、7的知識點。html
爲何要將六、7合在一塊兒寫呢?不是由於想偷懶...實際上是脫離一個場景和合適的開始去規劃組件等設計都是不合理的,多多少少都有點交集,因此將這 2 點融合在一塊兒是更利於學習和理解的,到這裏就已經不是太基礎的內容了,基本上代碼量會有所提升,可是分析依然會很細緻。前端
這裏用一個簡單的表格的添加
、刪除
、編輯
、搜索
四個功能來做爲實例吧。
由於這應該是平常開發過程當中遇到過程最多的,我將參考 bootstrap-table 的方式來開發一個簡單的表格組件和約定配置來作,感受比較自由,若是你動手能力好且業務稍大和複雜能夠參考 antd 設計規範來實現,目前市面上應該螞蟻這套用的比較多,可是這並不意味着咱們就必定是按照他來作,實際項目不復雜的狀況是可使用更簡單的方式。java
作這個開始以前,首先要假設一點場景和基本需求,這樣才能帶着去思考如何實現以及更接近需求目標。react
(1) 場景git
爲了更清晰的安排年前年後的工做和值班,如今要對過年期間人員請假的狀況進行統計,而且進行一個簡單的管理。github
(2) 功能性需求編程
簡單描述了一下,其實就以前說的幾個功能。json
最後作出來的效果以下(=.=沒有設計,對齊就行哈):
看以前能夠下載源代碼對照着看,不過代碼可能會不斷修改 BUG,哈哈~有 BUG 不要虛,沒有 BUG 咱們可能就失業了。
源碼-GitHub
(3) 準備工做
1. 須要用到的技術
須要用到的技術:React/ES6, CSS 便可
2. 基礎 UI 組件
根據咱們這裏的功能來看,咱們只須要下面這幾個基礎組件便可:Button
, Dialog
, Input
, Table
, Radio
在這個例子項目裏面,組件的劃分結構以下:
爲何要這樣劃分呢?
基礎組件:
其實這個是每個項目都須要的,若是說過小的項目不須要其實大多數是考慮掉了項目的迭代週期的考量以及之後代碼的可複用性,顧名思義,基礎組件就是你要在之後的組件編寫過程當中須要依賴的最基礎的組件,基本是隻負責 UI 層面的職責,固然你還可以再剝離,這裏就不太展開了,知道這一層是爲了之後寫組件可以有本身的基礎組件便可。業務組件、模塊組件:
在咱們開發好基礎組件事後,其實這些基礎組件是不具有任何業務價值的,好比有了業務設計稿後,咱們須要針對業務而後編寫業務中公用的組件或者封裝使用操做2次的組件代碼,造成一個可複用的業務組件或者業務模塊類型的組件。好比我這裏會將每一個模塊用到的模塊標題封裝成一個 ModTitle
組件,這樣之後修改這裏樣式的時候所有就在一個地方修改,或者在業務系統上會有 Layout
相關的佈局組件需求,再好比系統中表格整個一塊的需求,包含搜索、頭部操做按鈕、數據展現表格,這三者可以進行一個通用性的封裝來造成業務模塊上的表格使用組件,增長編寫模塊的效率,固然這裏我並無封裝,由於封裝和重構並非軟件初始開發更應該注重的,而是遇到第二次的時候再反過來思考如何避免重複或者讓組件內部封裝。展現組件、容器組件:
這一層就是網上流行的展現型組件、容器組件的一層,我這裏劃分主要是跟具體業務功能有關係的一層。因爲我這裏沒有 react-router
,因此複雜度會低一些,後面有時間也能夠介紹。3. bootstrap-table 生成表格的方式
能夠查看 github-bootstrap-table 的使用例子來看下使用方式,這裏我用它作例子並非說此庫徹底好或者很差,而是之前項目用了 bootstrap-table 而後就模仿了 columns 配置的方式,對於它 API 設計的其餘部分暫時沒采用。
表格組件實際上是管理類系統很核心的部分,一是用的多,二是自己也比較複雜,封裝太死缺乏靈活性,封裝太簡單缺乏效率,種類也比較多。大致上我會採用字段進行配置的方式,具體看後面的代碼和分析。
4. 項目的目錄規劃
上面介紹了一些概念性的東西,那麼項目主要的目錄單獨提一下,這裏的項目目錄不適合大型項目,可是須要一個這個過程,來理解每一項的意思以及爲何咱們還須要其餘技術來解決你遇到的問題,堆技術的作法是不可取的,至少在不瘋狂 KPI 模式的狀況下。
├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json ├── server // 網站後端的目錄,這裏咱們不須要關係 ├── src // 前端的源代碼目錄 │ ├── App.js // App 的入口組件 │ ├── apis // API 請求層的相關文件,Ajax 的方法也是須要適配的,好比常見的攔截器作法 │ ├── app.css │ ├── assets // 一些靜態資源 │ ├── components // 包含了業務組件、模塊組件、展現組件,這裏項目較小的時候不須要劃分太細,可是要有這樣的分層來組織代碼 │ ├── containers // 容器組件,主要的反作用等邏輯組件,基本上是數據初始化、維護一個較頂層的數據入口 │ ├── index.css │ ├── index.js // 網站的入口 JS 文件,主要是負責組件掛載到 DOM,或者你也能夠作一些全局注入的一些操做 │ ├── normalize.css │ ├── registerServiceWorker.js │ ├── smarty // 基礎組件的目錄,這裏我叫它 smarty,命名空間使用 st-,這個隨你高興 │ ├── stores // 數據操做的主要聚焦地方,每個 Store 都能是一個事件訂閱者,用於鏈接 React View 組件 │ └── utils // 一些工具輔助函數,目前我這裏沒有使用,真實項目確定會用上的
(4) 開始思考要如何開始寫代碼
要解決第一個問題,假設咱們的容器組件叫 EmployeeManage
,那麼在最外層的 App
組件中應該聲明要渲染它,代碼就會是這樣:
class App extends Component { render() { return ( <div className="App"> <EmployeeManage /> </div> ); } }
好了,假設這樣會出現最初的那個效果圖的樣子,那麼數據並不想寫的太過於零散,因此我定義了一個 Store
類進行管理,爲何是類呢?如今不是流行 Redux
之類函數式的麼?一是在最開始學習的時候增長太多技術棧心累,二是不必定要用 Redux
咱們才能寫好 React,三是感受也不太必要就咱們目前的需求來看,四是我就想最初簡簡單單的。
可是如今咱們是數據驅動方式的編程,數據變了來通知 React 的 state 變了而後 React 去幫咱們作視圖的更新,因此,咱們的 Store 得是一個基於事件的類,要有事件應該有的特徵:監聽。因此最後我須要一個 EmployeeStore
:
// 用下自帶的,你也能夠本身實現一個簡單的 import EventEmitter from 'events'; import assign from 'object-assign'; const state = {}; const EmployeeStore = assign({}, EventEmitter.prototype, { // 把容器組件的 this.state 在這裏管理 getState() { return state; } });
原始是原始了一點,可是應該很好理解,那就是個人 EmployeeStore
擁有了 EventEmitter.prototype
的東西,好比經常使用的 on()
, off()
, emit()
等方法來實現事件特性。
而後咱們須要把 EmployeeManage
和 EmployeeStore
鏈接起來,最簡單的鏈接像這樣子:
class EmployeeManage extends React.Component { constructor() { super(); // 看這裏 this.state = EmployeeStore.getState(); } }
鏈接了這個基礎的東西,咱們的 EmployeeStore
不是還能夠訂閱事件麼?而後數據修改了咱們就觸發一下訂閱的事件去告訴 EmployeeManage
而後經過 this.setState
去更新視圖便可,整個關係以下:
看圖可能就更直觀的知道數據和組件之間的關係了,用過 Flux
可能能夠發現還比較像,可是這是兩個不一樣的理念,我這裏只是一個最基礎的事件系統,因此會特別簡單。
咱們如今來訂閱一個名爲 updateList
的事件,用來表示表格中須要展現每條數據。咱們須要在 EmployeeManage
中加入下面的代碼:
componentDidMount() { EmployeeStore.on('updateList', this.handleUpdateList); } componentWillUnMount() { EmployeeStore.off('updateList', this.handleUpdateList); } handleUpdateList(list) { this.setState(prevState => { return { list: list, }; }); }
這三個方法能跟上面的圖對應一下,就對應上了 EmployeeManage
和 Component
,那麼咱們的 Store
須要怎麼作呢?
getList() { // API 請求列表數據的方法,返回一個 Promise EmployeeApi.get().then(result => { if(result.status === 200) { // 恰好,就通知了 EmployeeManage 說我數據獲取成功了,能夠更新視圖了 this.emit('updateList', result.data); } }); },
以上就完成了鏈接
工做了,基本上剩下的就是碼代碼,往上累積功能。先寫到這裏吧,太長看着也累,分一下章節吧~其實架子已經差很少了,剩下的就是寫功能點了。若是以爲看文章太慢能夠直接看源碼可能會更快更直接一點,沒有數據層,其實並非太好,先理解視圖和關係吧。