dva的初識(shí)


title: dva的初識(shí)
date: 2018-05-28 15:02:34
tags: dva


內(nèi)心獨(dú)白

這段時(shí)間以前的同事和我極力安利dva 這個(gè)框架运敢,我之前確實(shí)了解過骗炉,但是心想著遵倦,我會(huì)redux,看到一個(gè)技術(shù)文章介紹是什么極簡(jiǎn)的redux實(shí)現(xiàn)方式的標(biāo)題束亏,我就沒想深入去了解签则,何況,本著會(huì)react,redux,react-router,ant-design吃天下的原則拇泣。我就沒去深入了解噪叙,但是慢慢的接觸,我發(fā)現(xiàn)dva的框架做的事情真的很多霉翔,而且在很多方式簡(jiǎn)化了編程睁蕾。今天就了解第一步咱們的dva。

dva 是什么

詳細(xì)的介紹請(qǐng)看這里
這個(gè)其實(shí)是支付寶整合的一套框架早龟,集成了 (redux + react-router + redux-saga 等)的一層輕量封裝惫霸。dva 是 framework猫缭,不是 library,類似 emberjs壹店。
他最核心的是提供了 app.model 方法猜丹,用于把 reducer, initialState, action, saga 封裝到一起。

app.model({
  namespace: 'products',
  state: {
    list: [],
    loading: false,
  },
  subscriptions: [
    function(dispatch) {
      dispatch({type: 'products/query'});
    },
  ],
  effects: {
    ['products/query']: function*() {
      yield call(delay(800));
      yield put({
        type: 'products/query/success',
        payload: ['ant-tool', 'roof'],
      });
    },
  },
  reducers: {
    ['products/query'](state) {
      return { ...state, loading: true, };
    },
    ['products/query/success'](state, { payload }) {
      return { ...state, loading: false, list: payload };
    },
  },
});

現(xiàn)在來介紹一下這些key:
(假設(shè)你已經(jīng)熟悉了 redux, redux-saga 這一套應(yīng)用架構(gòu))

  • namespace - 對(duì)應(yīng) reducer 在 combine 到 rootReducer 時(shí)的 key 值
  • state - 對(duì)應(yīng) reducer 的 initialState
  • subscription - elm@0.17 的新概念硅卢,在 dom ready 后執(zhí)行射窒,這里不展開解釋
  • effects - 對(duì)應(yīng) saga,并簡(jiǎn)化了使用
  • reducers - 相當(dāng)于數(shù)據(jù)模型

安裝一個(gè)腳手架吧

dva-cli github的地址在這里:https://github.com/dvajs/dva-cli 将塑。

npm install dva-cli -g
dva new myapp && cd myapp
npm start

如果一切進(jìn)行的順利脉顿,那么基本上應(yīng)該是進(jìn)入到這個(gè)頁面

dva-demo

完成幾個(gè)demo ?

參考鏈接 - https://github.com/dvajs/dva-docs/blob/master/v1/zh-cn/getting-started.md

這里會(huì)教我們啟動(dòng)和開始一個(gè)demo 点寥,從而熟悉整個(gè)項(xiàng)目

如何去寫艾疟?

接到需求之后推薦的做法不是立刻編碼,而是先以上帝模式做整體設(shè)計(jì)敢辩。

  1. 先設(shè)計(jì) model
  2. 再設(shè)計(jì) component
  3. 最后連接 model 和 component

首先我們要先定義model

app.model({
  namespace: 'count',
  state: {
    record : 0,
    current: 0,
  },
});

namespace 是 model state 在全局 state 所用的 key蔽莱,state 是默認(rèn)數(shù)據(jù)。然后 state 里的 record 表示 highest record戚长,current 表示當(dāng)前速度盗冷。

其次設(shè)計(jì)component

完成 Model 之后,我們來編寫 Component 同廉。推薦盡量通過 stateless functions 的方式組織 Component仪糖,在 dva 的架構(gòu)里我們基本上不需要用到 state 。

import styles from './index.less';
const CountApp = ({count, dispatch}) => {
  return (
    <div className={styles.normal}>
      <div className={styles.record}>Highest Record: {count.record}</div>
      <div className={styles.current}>{count.current}</div>
      <div className={styles.button}>
        <button onClick={() => { dispatch({type: 'count/add'}); }}>+</button>
      </div>
    </div>
  );
};
  • 這里先 import styles from './index.less';迫肖,再通過 styles.xxx 的方式聲明 css classname 是基于 css-modules 的方式锅劝,后面的樣式部分會(huì)用上
  • 通過 props 傳入兩個(gè)值,count 和 dispatch咒程,count 對(duì)應(yīng) model 上的 state鸠天,在后面 connect 的時(shí)候綁定,dispatch 用于分發(fā) action
  • dispatch({type: 'count/add'}) 表示分發(fā)了一個(gè) {type: 'count/add'} 的 action

更新state

更新 state 是通過 reducers 處理的帐姻。

reducer 是唯一可以更新 state 的地方,這個(gè)唯一性讓我們的 App 更具可預(yù)測(cè)性奶段,所有的數(shù)據(jù)修改都有據(jù)可查饥瓷。reducer 是 pure function,他接收參數(shù) state 和 action痹籍,返回新的 state呢铆,通過語句表達(dá)即 (state, action) => newState。

這個(gè)需求里蹲缠,我們需要定義兩個(gè) reducer棺克,add 和 minus悠垛,分別用于計(jì)數(shù)的增和減。值得注意的是 add 時(shí) record 的邏輯娜谊,他只在有更高的記錄時(shí)才會(huì)被記錄确买。

請(qǐng)注意,這里的 add 和 minus 兩個(gè)action纱皆,在 count model 的定義中是不需要加 namespace 前綴的湾趾,但是在自身模型以外是需要加 model 的 namespace

app.model({
  namespace: 'count',
  state: {
    record: 0,
    current: 0,
  },
+ reducers: {
+   add(state) {
+     const newCurrent = state.current + 1;
+     return { ...state,
+       record: newCurrent > state.record ? newCurrent : state.record,
+       current: newCurrent,
+     };
+   },
+   minus(state) {
+     return { ...state, current: state.current - 1};
+   },
+ },
});

綁定數(shù)據(jù)

在定義了 Model 和 Component 之后,我們需要把他們連接起來派草。這樣 Component 里就能使用 Model 里定義的數(shù)據(jù)搀缠,而 Model 中也能接收到 Component 里 dispatch 的 action 。

這個(gè)需求里只要用到 count近迁。

function mapStateToProps(state) {
  return { count: state.count };
}
const HomePage = connect(mapStateToProps)(CountApp);

這里的 connect 來自 react-redux艺普。

路由

接收到 url 之后決定渲染哪些 Component,這是由路由決定的鉴竭。

這個(gè)需求只有一個(gè)頁面歧譬,路由的部分不需要修改。

app.router(({history}) =>
  <Router history={history}>
    <Route path="/" component={HomePage} />
  </Router>
);

樣式

默認(rèn)是通過 css modules 的方式來定義樣式拓瞪,這和普通的樣式寫法并沒有太大區(qū)別缴罗,由于之前已經(jīng)在 Component 里 hook 了 className,這里只需要在 index.less 里填入以下內(nèi)容:

.normal {
  width: 200px;
  margin: 100px auto;
  padding: 20px;
  border: 1px solid #ccc;
  box-shadow: 0 0 20px #ccc;
}

.record {
  border-bottom: 1px solid #ccc;
  padding-bottom: 8px;
  color: #ccc;
}

.current {
  text-align: center;
  font-size: 40px;
  padding: 40px 0;
}

.button {
  text-align: center;
  button {
    width: 100px;
    height: 40px;
    background: #aaa;
    color: #fff;
  }
}

異步處理

在此之前祭埂,我們所有的操作處理都是同步的面氓,用戶點(diǎn)擊 + 按鈕,數(shù)值加 1

現(xiàn)在我們要開始處理異步任務(wù)蛆橡,dva 通過對(duì) model 增加 effects 屬性來處理 side effect(異步任務(wù))舌界,這是基于 redux-saga 實(shí)現(xiàn)的,語法為 generator

在這個(gè)需求里泰演,當(dāng)用戶點(diǎn) + 按鈕呻拌,數(shù)值加 1 之后,會(huì)額外觸發(fā)一個(gè) side effect睦焕,即延遲 1 秒之后數(shù)值 1 藐握。

app.model({
  namespace: 'count',
+ effects: {
+   *add(action, { call, put }) {
+     yield call(delay, 1000);
+     yield put({ type: 'minus' });
+   },
+ },
...
+function delay(timeout){
+  return new Promise(resolve => {
+    setTimeout(resolve, timeout);
+  });
+}

  • add() {} 等同于 add: function(){}
  • call 和 put 都是 redux-saga 的 effects,call 表示調(diào)用異步函數(shù)垃喊,put 表示 dispatch action猾普,其他的還有 select, take, fork, cancel 等,詳見 redux-saga 文檔
  • 默認(rèn)的 effect 觸發(fā)規(guī)則是每次都觸發(fā)(takeEvery)本谜,還可以選擇 takeLatest初家,或者完全自定義 take 規(guī)則

訂閱鍵盤事件

在實(shí)現(xiàn)了鼠標(biāo)測(cè)速之后,怎么實(shí)現(xiàn)鍵盤測(cè)速呢?

在 dva 里有個(gè)叫 subscriptions 的概念,他來自于 elm溜在。

Subscription 語義是訂閱陌知,用于訂閱一個(gè)數(shù)據(jù)源,然后根據(jù)條件 dispatch 需要的 action掖肋。數(shù)據(jù)源可以是當(dāng)前的時(shí)間仆葡、服務(wù)器的 websocket 連接、keyboard 輸入培遵、geolocation 變化浙芙、history 路由變化等等。

dva 中的 subscriptions 是和 model 綁定的籽腕。

+import key from 'keymaster';
...
app.model({
  namespace: 'count',
+ subscriptions: {
+   keyboardWatcher({ dispatch }) {
+     key('?+up, ctrl+up', () => { dispatch({type:'add'}) });
+   },
+ },
});

這里我們不需要手動(dòng)安裝 keymaster 依賴嗡呼,在我們敲入 import key from 'keymaster'; 并保存的時(shí)候,dva-cli 會(huì)為我們安裝 keymaster 依賴并保存到 package.json 中

構(gòu)建應(yīng)用

我們已在開發(fā)環(huán)境下進(jìn)行了驗(yàn)證皇耗,現(xiàn)在需要部署給用戶使用南窗。敲入以下命令:

$ npm run build

輸出:

> @ build /private/tmp/dva-quickstart
> atool-build

Child
    Time: 6891ms
        Asset       Size  Chunks             Chunk Names
    common.js    1.18 kB       0  [emitted]  common
     index.js     281 kB    1, 0  [emitted]  index
    index.css  353 bytes    1, 0  [emitted]  index

該命令成功執(zhí)行后,編譯產(chǎn)物就在 dist 目錄下郎楼。

應(yīng)用源碼

應(yīng)用源碼:github地址

參考鏈接

dva-cli github地址
dva.js 知識(shí)導(dǎo)圖
dva 快速上手

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末万伤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子呜袁,更是在濱河造成了極大的恐慌敌买,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阶界,死亡現(xiàn)場(chǎng)離奇詭異虹钮,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)膘融,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門芙粱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人氧映,你說我怎么就攤上這事春畔。” “怎么了岛都?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵律姨,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我臼疫,道長(zhǎng)线召,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任多矮,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘塔逃。我一直安慰自己讯壶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布湾盗。 她就那樣靜靜地躺著伏蚊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪格粪。 梳的紋絲不亂的頭發(fā)上躏吊,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音帐萎,去河邊找鬼比伏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛疆导,可吹牛的內(nèi)容都是我干的赁项。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼澈段,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼悠菜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起败富,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤悔醋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后兽叮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芬骄,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年充择,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了德玫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡椎麦,死狀恐怖宰僧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情观挎,我是刑警寧澤琴儿,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站嘁捷,受9級(jí)特大地震影響造成,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜雄嚣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一晒屎、第九天 我趴在偏房一處隱蔽的房頂上張望喘蟆。 院中可真熱鬧,春花似錦鼓鲁、人聲如沸蕴轨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽橙弱。三九已至,卻和暖如春燥狰,著一層夾襖步出監(jiān)牢的瞬間棘脐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工龙致, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蛀缝,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓净当,卻偏偏與公主長(zhǎng)得像内斯,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子像啼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容