天天看點

mobx基礎及在react中的使用一、mobx入門二、webpack + mobx 環境配置

一、mobx入門

https://cn.mobx.js.org/

一、observable可觀察的狀态

https://cn.mobx.js.org/refguide/observable.html

map

import {observable} from 'mobx'
// 聲明
const map = observable.map({a: 1, b: 2});
// 設定
map.set('a', 11);
// 擷取
console.log(map.get('a'));//11
console.log(map.get('b'));//2
// 删除
map.delete('a');
console.log(map.get('a'));//undefined
// 判斷是否存在屬性
console.log(map.has('a'));//false
           

object

import {observable} from 'mobx'
// 聲明
const obj = observable({a: 1, b: 2});
// 修改
obj.a = 11;
// 通路
console.log(obj.a, obj.b);//11 2
           

array

import {observable} from 'mobx'
const arr = observable(['a', 'b', 'c', 'd']);
// 通路
console.log(arr[0], arr[10]);// "a"  undefined
// 操作
arr.pop();
arr.push('e');
           

列印數組的話是個proxy , 同時也具有數組的方法

mobx基礎及在react中的使用一、mobx入門二、webpack + mobx 環境配置

基礎類型

import {observable} from 'mobx'
const num = observable.box(10);
const str = observable.box('hello');
const bool = observable.box(true);
// 獲得值
console.log(num.get(), str.get(), bool.get());//10 hello true
// 修改值
num.set(100);
str.set('hi');
bool.set(false);
console.log(num.get(), str.get(), bool.get());//100 hi false
           

observable裝飾器

安裝

npm install --save-dev @babel/plugin-propsal-decorators @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime

每種類型的資料都需要用observable設定 , 這樣難免會很麻煩 , 這時候我們就可以用裝飾器

import {observable} from 'mobx'

// observable這個函數可以識别當成普通函數調用還是裝飾器調用
// 如果是裝飾器,會自動識别資料類型,使用不同的包裝轉換方案。
class Store{
  @observable arr = [];
  @observable obj = {a: 1};
  @observable map = new Map();
  @observable str = 'hello';
  @observable num = 123;
  @observable bool = false;
}

const store = new Store();

console.log(store);
console.log(store.obj.a);
           

注意:vscode編譯器中,js檔案使用裝飾器會報紅。解決方式:

在根目錄編寫jsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "experimentalDecorators": true
  },
  "include": ["src/**/*"]
}
           

二、對 observables 作出響應

1. computed

計算值是可以根據現有的狀态或其它計算值衍生出的值, 跟vue中的computed非常相似。

import {observable,computed} from 'mobx'
class Store{
  @observable arr = [];
  @observable obj = {a: 1};
  @observable map = new Map();
  @observable str = 'hello';
  @observable num = 123;
  @observable bool = false;
}
const store = new Store();

const result = computed(()=>{
	console.log(1)//初始化會執行一次  修改也會執行
	store.str + store.num
})
console.log(result.get());

// 監聽資料的變化
result.observe((change)=>{
  console.log('result:', change);//列印兩次   因為store修改了兩次
})
//兩次對store屬性的修改都會引起result的變化
store.str = 'world';
store.num = 220;

           

computed可作為裝飾器, 将result的計算添加到類中:

class Store{
  @observable arr = [];
  @observable obj = {a: 1};
  @observable map = new Map();

  @observable str = 'hello';
  @observable num = 123;
  @observable bool = false;

  @computed get result(){
    return this.str + this.num;
  }  
}
           

2. autorun

當你想建立一個響應式函數,而該函數本身永遠不會有觀察者時,可以使用

mobx.autorun

所提供的函數總是立即被觸發一次,然後每次它的依賴關系改變時會再次被觸發。

經驗法則:如果你有一個函數應該自動運作,但不會産生一個新的值,請使用autorun。 其餘情況都應該使用 computed。

//aotu會立即觸發一次
autorun(()=>{
  console.log(store.str + store.num);
})

autorun(()=>{
  console.log(store.result);
})
//兩次修改都會引起autorun執行
store.num = 220;
store.str = 'world';
           

3. when

when(predicate: () => boolean, effect?: () => void, options?)

when 觀察并運作給定的 predicate,直到傳回true。 一旦傳回 true,給定的 effect 就會被執行,然後 autorunner(自動運作程式) 會被清理。 該函數傳回一個清理器以提前取消自動運作程式。

對于以響應式方式來進行處理或者取消,此函數非常有用。

when(()=>store.bool, ()=>{
  console.log('when function run.....');
})
store.bool = true;
           

4. reaction

用法:

reaction(() => data, (data, reaction) => { sideEffect }, options?)

autorun 的變種,對于如何追蹤 observable 賦予了更細粒度的控制。

它接收兩個函數參數,第一個(資料 函數)是用來追蹤并傳回資料作為第二個函數(效果 函數)的輸入。

不同于 autorun 的是當建立時效果 函數不會直接運作,隻有在資料表達式首次傳回一個新值後才會運作。 在執行 效果 函數時通路的任何 observable 都不會被追蹤。

// reaction  第一個參數的傳回值作為第二個參數的輸入
reaction(()=>[store.str, store.num], (arr)=>{
  console.log(arr.join('/')); // world/220
})
//隻要[store.str, store.num]中任意一值發生變化,reaction第二個函數都會執行
store.num = 220;
store.str = 'world';
           

三、改變 observables狀态

1. action

接上面案例,添加action到類中:

class Store{
  @observable arr = [];
  @observable obj = {a: 1};
  @observable map = new Map();

  @observable str = 'hello';
  @observable num = 123;
  @observable bool = false;
  
  //擷取資料@computed
  @computed get result(){
    return this.str + this.num;
  }
//修改資料@action
  @action bar(){
    this.str = 'world';
    this.num = 40;
  }
}
const store = new Store();

//調用action,隻會執行一次
store.bar();
           

2. action.bound

action.bound

可以用來自動地将動作綁定到目标對象。

class Store{
  @observable arr = [];
  @observable obj = {a: 1};
  @observable map = new Map();

  @observable str = 'hello';
  @observable num = 123;
  @observable bool = false;

  @computed get result(){
    return this.str + this.num;
  }

  @action bar(){
    this.str = 'world';
    this.num = 40;
  }

  //this 永遠都是正确的
  @action.bound foo(){
    this.str = 'world';
    this.num = 40;
  }
}

const store = new Store();
setInterval(store.foo, 1000)
           

3. runInAction

action

隻能影響正在運作的函數,而無法影響目前函數調用的異步操作。如果你使用async function來處理業務,那麼我們可以使用

runInAction

這個API來解決這個問題。

@action async fzz() {
  await new Promise((resolve) => { 
    setTimeout(() => {
      resolve(0)
    }, 1000) 
  })
  runInAction(()=>{
    store.num = 220
    store.str = 'world'
  })    
}
           

四、react-native + mobx案例 todolist

實作效果

mobx基礎及在react中的使用一、mobx入門二、webpack + mobx 環境配置

1、 安裝

mobx

mobx-react

(将react和mobx銜接)以及配置裝飾器

npm install mobx mobx-react --save-dev

配置裝飾器具體步驟https://blog.csdn.net/weixin_44157964/article/details/108292457

2、建立一個store/index.js

mobx基礎及在react中的使用一、mobx入門二、webpack + mobx 環境配置

3、

App.js

中導入

store/index.js

, 并且導入

mobx-react

, 使用

Provider

包裹元件

mobx基礎及在react中的使用一、mobx入門二、webpack + mobx 環境配置

4、頁面中使用mobx

inject

store

注入到目前類元件的屬性中

observer

觀測

render

函數中用了哪些可觀察狀态 , 如果

store

中的值有變化 ,

render

函數就會重新渲染

mobx基礎及在react中的使用一、mobx入門二、webpack + mobx 環境配置

二、webpack + mobx 環境配置

mkdir mobx-demo
cd mobx-demo
npm init -y
npm i webpack webpack-cli webpack-dev-server -D
npm i html-webpack-plugin -D
npm i babel-loader @babel/core @babel/preset-env -D
npm i @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties -D
npm i @babel/plugin-transform-runtime -D
npm i @babel/runtime -S
npm i mobx -S
mkdir src
touch index.html
touch src/index.js
           

編寫webpack.config.js

const path = require('path')
const htmlwebpackplugin = require('html-webpack-plugin')

module.exports = {
  mode:"development",
  devtool:"inline-source-map",
  entry:"./src/index.js",
  output:{
    path:path.resolve(__dirname,'./dist'),
    filename:'[name]-[hash].js'
  },
  devServer:{
    contentBase: path.join(__dirname, 'dist'),
    compress: true,
    port: 9000,
    open:true
  },
  module:{
    rules:[
      {
        test:/\.js$/,
        exclude:/node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            "plugins": [
              //支援裝飾器
              ["@babel/plugin-proposal-decorators", { "legacy": true }],
              ["@babel/plugin-proposal-class-properties", { "loose" : true }],
              ["@babel/plugin-transform-runtime"]
            ]
          }
        }
      }
    ]
  },

  plugins:[new htmlwebpackplugin({
    filename:'index.html',
    template:'./index.html'
  })]

}
           

編寫index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

</body>
</html>
           

繼續閱讀