這邊文章主要目的呢。是搭建一個react和mobx的demo。能夠了解mobx在react應用中如何使用的。我會用大白話的形式寫這個文章; 文末有react 和react-native 的兩個整合mobx的專案demo。react-native的實現思路和下面一樣。
#####1.create-react-app建立react專案 腳手架命令生成一個專案:
1.create-react-app react_mobx
//建立好腳手架安裝mobx和mobx-react 包
2. npm install mobx mobx-react --save
3. npm install react-router --save
複製程式碼
安裝好上面依賴。我們修改下專案結構----大家可以自行修改下;
#####2.實現react-router功能
大家都知道mobx可以解跨頁面共享資料的問題。那我們先實現跳轉頁面功能;我們先修改下下面幾個檔案--
1.home.jsx
import React, { Component } from "react";
class Home extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div>
<h1>首頁</h1>
<button onClick={() => { this.props.history.push("/one");}}>
跳轉到第一個頁面
</button>
</div>
);
}
}
export default Home
複製程式碼
2.one.jsx
import React, { Component } from "react";
class One extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div>
<h1>頁面一</h1>
<button onClick={() => { this.props.history.push("/");}}>
跳轉到首頁
</button>
</div>
);
}
}
export default One
複製程式碼
3.router.jsx
import React, { Component, Fragment } from "react";
import { HashRouter,Route } from "react-router-dom";
import Home from '../page/home';
import One from '../page/one';
class Router extends Component {
render() {
return (
<HashRouter>
<Fragment>
<Route exact path={`/`} component={Home} />
<Route path={`/one`} component={One} />
</Fragment>
</HashRouter>
);
}
}
export default Router;
複製程式碼
4.index.js 檔案入口
import React from 'react';
import ReactDOM from 'react-dom';
import Router from './router/router';
ReactDOM.render(<Router />, document.getElementById('root'));
複製程式碼
好了檔案修改完畢~ npm start
一下,頁面是不是可以自由跳轉了呢~ 好了 實現了這個我們就進行下一步吧
重要提醒--MobX採用的是ES7的裝飾器語法,目前還是一種實驗性的語法,使用 create-react-app 腳手架預設建立的專案是沒有開啟裝飾器語法的。需要一些額外的配置檢視下這篇文章:
create-react-app配置修飾器
可能這個方法比較麻煩-----我現在解決方案是這個--有好的辦法 我會及時更新的~
#####3.mobx和mobx-react的使用 3.1需要專案結構src下增加一個store資料夾 --這個資料夾的作用。我們理解為專門存放和管理資料來源的地方;
建立3個js檔案- homeStore.js、oneStore.js、index.js 下面對每個資料夾進行新增程式碼
homeStore.js: 存放一個頁面資料來源的類
import { observable} from "mobx";
class HomeStore {
@observable homeNum = 0;
}
export default HomeStore;
複製程式碼
oneStore.js: 存放一個頁面資料來源的類
import { observable} from "mobx";
class OneStore {
@observable oneNum = 3333;
}
export default OneStore;
複製程式碼
index.js: 將多個store融合到一個物件裡面
import HomeStore from "./homeStore";
import OneStore from "./oneStore";
let oneStore = new OneStore();
let homeStore = new HomeStore();
const stores = {
oneStore,
homeStore
};
/// 預設匯出介面
export default stores;
複製程式碼
這些資料夾建立的意義是什麼呢。其實一個xxxStore的話 就是一個資料來源的地方。每個類裡面可以定義我們需要用到的資料-就和我們react中state一樣;index.js的作用呢 就是把所有資料整合到一塊去-- 其實也是為了下面一部做鋪墊的;
3.2 專案入口index.js部分程式碼修改
index.js
import React from "react";
import ReactDOM from "react-dom";
import Router from "./router/router";
import { Provider } from "mobx-react";
import stores from "./store";
ReactDOM.render(
<Provider {...stores}>
<Router />
</Provider>,
document.getElementById("root")
);
複製程式碼
這邊我們引入 Provider 和上面提及到的store 。這邊其實就是一個資料容器,也是mobx這一類資料流框架實現資料共享的基礎。
我們子元件放在這個資料容器當中。mobx才可以做到跨元件資料共享Provider 這個其實不陌生了。其實就是react中context 中的屬性--自己寫的關於react Context的文章 不瞭解的同學可以學習一下。
3.3 page/home.jsx 的程式碼修改 既然Provider是資料容器。我們子元件在容器裡面。那我們子元件是如何使用容器裡面的資料呢--看一下下面程式碼
import React, { Component } from "react";
+ import { observer, inject } from "mobx-react";
+ @inject("homeStore")
+ @observer
class Home extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div>
+ <h1>首頁資料來源的number為:{this.props.homeStore.homeNum}</h1>
<button onClick={() => { this.props.history.push("/one") }}>
跳轉到第一個頁面
</button>
</div>
);
}
}
export default Home;
複製程式碼
程式碼中+
就是新新增的程式碼 。下面介紹一下我們用到的幾個熟悉吧
observer:
將你的元件變成響應式元件。就是資料改變時候可以出發重新的渲染。
inject(homeStore):
和redux的connect作用一樣,將資料註冊到元件。homeStore其實就我們store/index中 new出來的例項名稱;
this.props.homeStore.xxx
:這個就是如何使用資料來源中的值.就和元件透傳一樣
3.4 資料來源如何修改?
既然上文我們實現了資料的展示,那麼當然少不了運算元據的操作-我們就進行下一個操作
@action:
請求的意思-在嚴格模式下。這是唯一操作store的操作;
+代表新增程式碼
- 修改store/homeStore.js
修改資料來源
//homeStore.js
import { observable,action} from "mobx";
class HomeStore {
@observable homeNum = 0;
+ @action addNum() {
+ this.homeNum += 1;
+ }
+ @action lessNum() {
+ this.homeNum -= 1;
+ }
}
export default HomeStore;
複製程式碼
- 修改page/home.jsx
展示增加操作按鈕
store裡面定義的@action這邊就用this.props.home.addNum()
操作就可以了
render() {
return (
//程式碼自行新增。。。。。。
+ <div>
+ <h1>首頁資料來源的number為:{this.props.homeStore.homeNum}</h1>
+ <button onClick={() => {this.props.homeStore.addNum()}} >
+ 點選新增
+ </button>
+ <button onClick={() => {this.props.homeStore.lessNum()}}>
+ 點選刪除
+ </button>
+ </div>
//程式碼自行新增。。。。。。
);
}
}
export default Home;
複製程式碼
3.5 共享的資料怎麼使用?
展示和修改的操作都完成了--那麼我們下一步應該是mobx共享資料了。如何實現資料共享呢。其實很簡單 我們直接看程式碼-在我們需要用到的資料來源頁面上加上@inject("homeStore")
就可以了---當然修改共享資料 也是
import React, { Component } from "react";
import { observer, inject } from "mobx-react";
@inject("homeStore")
@inject("oneStore")
@observer
class One extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div>
<h1>頁面一</h1>
<h1>首頁資料來源的number為:{this.props.homeStore.homeNum}</h1>
<h1>oneStore的number為:{this.props.oneStore.oneNum}</h1>
<button onClick={() => { this.props.history.push("/");}}>
跳轉到首頁
</button>
</div>
);
}
}
export default One
複製程式碼
去第二個頁面檢視一下資料展示:
這樣一套流程結束啦~
#####4.嚴格模式的設定 如果我們不適用嚴格模式的話。你可以有這麼一個騷操作;在頁面中使用下放程式碼:
this.props.homeStore.homeNum = 33;
複製程式碼
你會發現你的資料來源資料被修改過了~很方便對吧。but這是很危險的操作
資料來源就變得不可追溯了~ 那麼如何設定的-也是很簡單的啦~
專案入口index.js
+ import { configure } from "mobx";
//程式碼自行增加
render(
<div>
<Provider {...stores}>
<XXX />
</Provider>
</div>,
document.getElementById("root")
);
//5.x版本嚴格模式開啟方式
+ configure({
+ enforceActions: "observed"
+ });
複製程式碼
這樣開啟嚴格模式就可以了---這樣的好處呢就是運算元據源的唯一操作就是通過action。資料流變得可追溯了~
todo:程式碼還是有很多需要優化的地方 1.@observer不能放置在export default前 2.對於create-react-react 修飾器的支援感覺有點麻煩了
好了文章到處結束了; 寫的比較簡單。如果有寫的不對的地方歡迎指正--
下面給一下git地址--
自己寫了2個demo 一個是自己手動搭建webpack的demo 一個是腳手架生成的demo
自己手動webpack-mobx專案
create-react-app專案
react-native 整合mobx專案
自己無聊寫的小程式 歡迎提bug