dva - Route Components

dva實(shí)踐

學(xué)習(xí)react,快速入門(mén)的練習(xí)

創(chuàng)建引用可以直接使用dva-cli的各項(xiàng)命令快速創(chuàng)建項(xiàng)目.

項(xiàng)目開(kāi)始前的配置:

  1. 配置antd

    npm i antd --save
    npm i babel-plugin-inmport --save-dev  //按需加載插件
    
    1. .roadhogrc 的"exreaBabelPlugins"里加上語(yǔ)句
      ["import", { "libraryName": "antd", "style": "css" }]

dva-cli 的常用命令
dva g model users
dva g component Mainlayout/Header

使用封裝的loading

安裝:cnpm i dva-loading --save

切換路由:

 dispatch(routerRedux.push({
    pathname:'/users',
    query:{page},
  }))
  • ES6 寫(xiě)法
import React, { Component, PropTypes } from 'react';
import { Popover, Icon } from 'antd';

class PreviewQRCodeBar extends Component { // 組件的聲明方式
  constructor(props) { // 初始化的工作放入到構(gòu)造函數(shù)
    super(props); // 在 es6 中如果有父類,必須有 super 的調(diào)用用以初始化父類信息

    this.state = { // 初始 state 設(shè)置方式
      visible: false,
    };
  }
  // 因?yàn)槭穷?,所以屬性與方法之間不必添加逗號(hào)
  hide() {
    this.setState({
      visible: false,
    });
  }

  handleVisibleChange(visible) {
    this.setState({ visible });
  }

  render() {
    const { dataurl } = this.props;
    return (
      <Popover
        placement="rightTop"
        content={<img src={dataurl} alt="二維碼" />}
        trigger="click"
        visible={this.state.visible}
        onVisibleChange={this.handleVisibleChange.bind(this)} // 通過(guò) .bind(this) 來(lái)綁定
      >
        <Icon type="qrcode" />
      </Popover>
    );
  }
}
// 在 react 寫(xiě)法中,直接通過(guò) propTypes {key:value} 來(lái)約定
PreviewQRCodeBar.proptypes = {
  dataurl: PropTypes.string.isRequired,
};

// 在 ES6 類聲明中無(wú)法設(shè)置 props 只能在類的駐外使用 defaultProps 屬性來(lái)完成默認(rèn)值的設(shè)定
// 而在 react 中則通過(guò) getDefaultProps(){} 方法來(lái)設(shè)定
PreviewQRCodeBar.defaults = {
  // obj
}

export default PreviewQRCodeBar;

  • Stateless 寫(xiě)法
import React, { PropTypes } from 'react';

// 組件無(wú) state,pure function
const PreviewDevToolWebview = ({ remoteUrl }) => // 箭頭函數(shù),結(jié)構(gòu)賦值
  <webview className={devToolWebview.devToolWebview} src={remoteUrl} />;

PreviewDevToolWebview.proptype = {
  remoteUrl: PropTypes.string.isRequired,
};

export default PreviewDevToolWebview;

// 此類組件不支持 ref 屬性,沒(méi)有組件生命周期的相關(guān)的時(shí)候和方法,僅支持 propTypes
// 此類組件用以簡(jiǎn)單呈現(xiàn)數(shù)據(jù)

理解dva中的數(shù)據(jù)流

pic

如何來(lái)理解呢?

在 web 應(yīng)用中,數(shù)據(jù)的改變通常發(fā)生在用戶交互行為或者瀏覽器行為(如路由跳轉(zhuǎn)等),當(dāng)此類行為改變數(shù)據(jù)的時(shí)候可以通過(guò) dispatch 發(fā)起一個(gè) action,如果是同步行為會(huì)直接通過(guò) Reducers 改變 State ,如果是異步行為會(huì)先觸發(fā) Effects 然后流向 Reducers 最終改變 State,所以在 dva 中,數(shù)據(jù)流向非常清晰簡(jiǎn)明,并且思路基本跟開(kāi)源社區(qū)保持一致。

Action

Action 是一個(gè)普通 javascript 對(duì)象,它是改變 State 的唯一途徑。無(wú)論是從 UI 事件、網(wǎng)絡(luò)回調(diào),還是 WebSocket 等數(shù)據(jù)源所獲得的數(shù)據(jù),最終都會(huì)通過(guò) dispatch 函數(shù)調(diào)用一個(gè) action,從而改變對(duì)應(yīng)的數(shù)據(jù)。** 需要注意的是 dispatch 是在組件 connect Models以后,通過(guò) props 傳入的。**

dispatch({
  type: 'user/add', // 如果在 model 外調(diào)用,需要添加 namespace
  payload: {}, // 需要傳遞的信息
});

以上調(diào)用函數(shù)內(nèi)的對(duì)象就是一個(gè) action。

dispatch 函數(shù)

用于觸發(fā) action 的函數(shù),action 是改變 State 的唯一途徑,但是它只描述了一個(gè)行為,而 dipatch 可以看作是觸發(fā)這個(gè)行為的方式,而 Reducer 則是描述如何改變數(shù)據(jù)的。

dva - Reducer

在 dva 中,reducers 聚合積累的結(jié)果是當(dāng)前 model 的 state 對(duì)象。通過(guò) actions 中傳入的值,與當(dāng)前 reducers 中的值進(jìn)行運(yùn)算獲得新的值(也就是新的 state)。需要注意的是 Reducer 必須是純函數(shù)。

app.model({
  namespace: 'todos', //model 的 namespace
  state: [], // model 的初始化數(shù)據(jù)
  reducers: {
    // add 方法就是 reducer,可以看到它其實(shí)非常簡(jiǎn)單就是把老的 state 和接收到的數(shù)據(jù)處理下,返回新的 state
    add(state, { payload: todo }) {
      return state.concat(todo);
    },
  },
};

dva - Effect

Effect 被稱為副作用,在我們的應(yīng)用中,最常見(jiàn)的就是異步操作,Effects 的最終流向是通過(guò) Reducers 改變 State。

核心需要關(guān)注下 put, call, select。

app.model({
  namespace: 'todos',
  effects: {
    *addRemote({ payload: todo }, { put, call, select }) {
      const todos = yield select(state => state.todos); // 這邊的 state 來(lái)源于全局的 state,select 方法提供獲取全局 state 的能力,也就是說(shuō),在這邊如果你有需要其他 model 的數(shù)據(jù),則完全可以通過(guò) state.modelName 來(lái)獲取
      yield call(addTodo, todo); // 用于調(diào)用異步邏輯,支持 promise 。
      yield put({ type: 'add', payload: todo }); // 用于觸發(fā) action 。這邊需要注意的是,action 所調(diào)用的 reducer 或 effects 來(lái)源于本 model 那么在 type 中不需要聲明命名空間,如果需要觸發(fā)其他非本 model 的方法,則需要在 type 中聲明命名空間,如 yield put({ type: 'namespace/fuc', payload: xxx });
    },
  },
});

dva - Subscription

Subscriptions 是一種從 獲取數(shù)據(jù)的方法,它來(lái)自于 elm。

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

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

dva - Router

這里的路由通常指的是前端路由,由于我們的應(yīng)用現(xiàn)在通常是單頁(yè)應(yīng)用,所以需要前端代碼來(lái)控制路由邏輯,通過(guò)瀏覽器提供的 History API 可以監(jiān)聽(tīng)瀏覽器url的變化,從而控制路由相關(guān)操作。

dva 實(shí)例提供了 router 方法來(lái)控制路由,使用的是react-router

import { Router, Route } from 'dva/router';
app.router(({history}) =>
  <Router history={history}>
    <Route path="/" component={HomePage} />
  </Router>
);

在 dva 中我們通常以頁(yè)面維度來(lái)設(shè)計(jì) Container Components。

所以在 dva 中,通常需要 connect Model的組件都是 Route Components,組織在/routes/目錄下,而/components/目錄下則是純組件(Presentational Components)。

** 通過(guò) connect 綁定數(shù)據(jù) **

比如:

import { connect } from 'dva';
function App() {}

function mapStateToProps(state, ownProps) { // 該方法名已經(jīng)非常形象的說(shuō)明了 connect 的作用在于 State -> Props 的轉(zhuǎn)換,同時(shí)自動(dòng)注冊(cè)一個(gè) dispatch 的方法,用以觸發(fā) action
  return {
    users: state.users,
  };
}
export default connect(mapStateToProps)(App);

然后在 App 里就有了 dispatchusers 兩個(gè)屬性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容