Dva 初讀文件學習
基於Redux-saga的資料管理方案,Redux-Saga 詳見文章《Redux中介軟體之redux-saga》
1、資料流向
概念:資料的改變通常是由於使用者互動行為或者瀏覽器行為觸發的,利用dispatch發起action(操作),然後通過一系列改變state
(1)同步:通過Reducer直接改變state
(2)非同步:先觸發Effects,然後流向Reducer,然後由Reducer最終改變state
2、Models
(1)State--資料狀態
State表示Model的狀態資料,通常為一個JavaScript物件
const app = dva(); console.log(app._store); // 頂部的 state 資料
(2)Action--改變state的唯一途徑
action是一個普通js物件,是改變state的唯一途徑,通過dispatch呼叫一個action,從而改變對應的state資料。action必須帶有type、其他引數自定義。要發起一個action必須要通過dispatch進行呼叫。
**注意:dispatch是要在元件connectModel之後,通過props傳入的,**
dispatch({
type: 'add',
});
dispatch內的物件就是一個action
(3)dispatch函式--實現action的方法
dispatch函式是用於觸發action(實現action)物件的一個函式,action是改變state的唯一途徑,但是action只是描述了這個行為,真正需要dispatch來觸發這個行為。
dva裡面,元件connect Model後就可以利用props訪問dispatch,然後dispatch就又可以呼叫Model裡面的Effects然後呼叫Reducer或者直接呼叫Reducer改變state的狀態
dispatch({
type: 'user/add',
payload:{}
})
(4)Reducer--描述和具體實現資料改變
Reducer函式接受兩個引數,之前已經累積運算的結果和當前要被累積的值,返回一個新的結果(兩個引數:當前值,和操作)
在Dva裡面,第一個引數聚合累積的結果就是當前model的state,通過action傳入的值,和當前reducer裡面的值進行運算,返回新的state。Reducer必須是純函式,同樣的輸入,輸出值必然一樣。
reducers: {
// reducer執行函式
'delete' ( state, { payload: id } ) {
// 返回陣列state裡面不等於傳入id的值,構建一個新陣列,可以實現刪除傳入id這項
return state.filter(item => item.id !== id)
}
}
(5)Effect
Action 處理器,處理非同步動作,基於 Redux-saga 實現。Effect 指的是副作用。根據函數語言程式設計,計算以外的操作都屬於 Effect,典型的就是 I/O 操作、資料庫讀寫。
dva 為了控制副作用的操作,底層引入了redux-sagas做非同步流程控制,由於採用了generator的相關概念,所以將非同步轉成同步寫法,從而將effects轉為純函式。
effects: {
*fetchFront ( { payload }, { call, put } ) {
const response = yield call( query, 'frontservice', { query: frontQuery, variables: payload.variables } );
yield put({
type: 'saveFront',
payload: response.data,
});
}
},
yield:標識每一步的操作
call:執行非同步函式
put:發出Action,使用put(類似於dispatch),操作reducer,改變state
(6)Subscription
Subscription是一種從源獲取資料的方法,來自於elm
Subscription語義是訂閱,用於訂閱一個數據源,然後根據相應的條件dispatch需要的action。資料來源可以是當前的時間、伺服器的 websocket 連線、keyboard 輸入、geolocation 變化、history 路由變化等等
import key from 'keymaster';
...
app.model({
namespace: 'count',
subscriptions: {
keyEvent({dispatch}) {
key('⌘+up, ctrl+up', () => { dispatch({type:'add'}) });
},
}
});
(*)例項
下面是一個完整的Model的例子
export default {
namespace: 'example',
state: {},
subscriptions: {
setup({ dispatch, history }) { // eslint-disable-line
},
},
effects: {
*fetch({ payload }, { call, put }) { // eslint-disable-line
//非同步操作
yield call({delay,1000})
//發出Action
yield put({ type: 'save' });
},
},
reducers: {
save(state, action) {
return { ...state, ...action.payload };
},
},
};
3、Router
這裡的路由指的是前端路由,spa應用裡面,需要由前端程式碼控制路由邏輯,控制路由相關操作
import React from 'react';
import { Router, Route, Switch } from 'dva/router';
//引入component
import IndexPage from './routes/IndexPage';
import Products from './routes/Product'
function RouterConfig({ history }) {
return (
<Router history={history}>
<Switch>
<Route path="/" exact component={ IndexPage } />
<Route path="/products" exact component={ Products}/>
</Switch>
</Router>
);
}
export default RouterConfig;
dva提供了router來控制路由,使用react-router
4、Router Components
在 dva 中,通常需要 connect Model的元件都是 Route Components,組織在/routes/目錄下,作為頁面元件;
而/components/目錄下則是純元件(Presentational Components),一般作為通用元件
- roadhog
文件地址:https://github.com/sorrycc/roadhog
Roadhog是一個包含dev,build和test的命令列工具,基於react-dev-utils,可以理解為可配置版的create-react-app。
- propTypes
使用propTypes進行型別檢查,驗證和確保元件接受到的props是有效的資料型別,當傳入的 prop
值型別不正確時,JavaScript 控制檯將會顯示警告。出於效能方面的考慮,propTypes
僅在開發模式下進行檢查。
import React from "react";
import PropTypes from "prop-types";
// 純函式元件寫法(傳入刪除和列表陣列pros)
class ProductList extends React.Component{
render(){
...
}
}
// propTypes檢查
ProductList.propTypes = {
//檢查資料型別並且是必須的
onDelete: PropTypes.func.isRequired,
products: PropTypes.array.isRequired
};
export default ProductList;