欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

原生微信小程序開發(fā)中 redux 的使用 - 新聞資訊 - 云南小程序開發(fā)|云南軟件開發(fā)|云南網(wǎng)站建設-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設/小程序開發(fā)/軟件開發(fā)

知識

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價值,我們在追求其視覺表現(xiàn)的同時,更側(cè)重于功能的便捷,營銷的便利,運營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序為后期升級提供便捷的支持!

您當前位置>首頁 » 新聞資訊 » 小程序相關(guān) >

原生微信小程序開發(fā)中 redux 的使用

發(fā)表時間:2021-2-20

發(fā)布人:葵宇科技

瀏覽次數(shù):123

前提

復雜場景中有不少數(shù)據(jù)需要在多個不同頁面間來回使用和修改。但是小程序頁面直接的數(shù)據(jù)通信方式十分的簡單。通常情況需要自己維護一個全局的對象來存放共有數(shù)據(jù)。但是,簡單的維護一個共有數(shù)據(jù)實體,會隨著業(yè)務邏輯的不斷復雜化而變的過分龐大,并且數(shù)據(jù)的修改往往無法很好的溯源。加之公共數(shù)據(jù)實體中數(shù)據(jù)的修改和頁面的UI之間沒有太好的同步手段,往往需要在頁面和對應的數(shù)據(jù)實體中同時都維護一份相同的數(shù)據(jù),操作十分的不方便。

之前使用過Taro以react+redux的結(jié)構(gòu)來開發(fā)微信小程序,依托redux整體上可以解決上述的問題。但是Taro本身也有著一些讓人無法接受的潛在問題。本著能用原生就絕不使用第三方二次封裝的庫的原則。一直想嘗試一下在原生微信小程序開發(fā)中接入redux。

需要解決的問題

1、redux庫的接入
2、頁面UI與redux數(shù)據(jù)的綁定
復制代碼
redux庫的引入

1、redux的安裝,使用 npm與yarn 都可以。

2、微信小程序引入外部npm包。

使用微信小程序IDEA,tools 中的 Build npm,生成miniprogram_npm

3、redux庫ReferenceError: process is not defined報錯的解決。

因為微信小程序Build npm工具,構(gòu)建時不會引入nodeprocess環(huán)境變量,但是redux對不同env做了對應的優(yōu)化。所以導致構(gòu)建出來的包缺失process變量。最便捷的解決方法是在構(gòu)建完成的包中自己注入需要的process

這樣基本可以解決所有第三方庫遇到的process參數(shù)缺失的問題。如果每次運行Build npm工具后都需要手動修改。如果有多個第三方庫需要手動修改,那就很麻煩。所以很有必要通過腳本,使用ast樹等工具完整動態(tài)修改,節(jié)省人力成本(這個后續(xù)介紹)

綜上,redux的引入就完成了。


在項目中添加redux

1、store的創(chuàng)建

使用combineReducers合并不同的實體,使用createStore創(chuàng)建store實體,并導出。為了數(shù)據(jù)的統(tǒng)一性,redux的原則是一個項目只初始化一個store,所以后續(xù)任何的操作都是在當前生成的store中進行。

合并數(shù)據(jù)實體:

const { combineReducers } = require('redux');
const testItem = require('./testItem/index');
const testItem2 = require('./testItem2/index');
const user = require('./user/index');

const reducer = combineReducers({
  testItem: testItem.testItem,
  testItem2,
  user
});

module.exports = {
  reducer
}

復制代碼

導出store:

const { createStore, applyMiddleware } = require('redux');
const { reducer } = require('./reducers');
const { logger } = require('redux-logger');

const store = createStore(
  reducer,
  applyMiddleware(logger)
)

module.exports = {
  store
}
復制代碼

2、全局維護store

這里和react中的使用方法不同。微信小程序沒有對應的控件來全局維護store,所以我的做法是直接在,app.jsglobalData中維護,這樣每個頁面都可以直接獲取到store

app.js:

const { store } = require('./redux/index');

//app.js
App({
  globalData: {
    $store: store,
    getState: ()=> store.getState(),
  }
})
復制代碼

模擬connect方法

在react中,connect方法是通過高階組件的方式實現(xiàn)的,但是這個方法并不適用微信小程序。好在redux有提供subscribe方法來監(jiān)聽store中數(shù)據(jù)的變化。所以初步設計:

1、每當頁面計入或顯示的時候,添加監(jiān)聽,頁面隱藏或銷毀時銷毀監(jiān)聽
2、添加完監(jiān)聽后,模擬 mapState 方法,把對應 redux 中的數(shù)據(jù)注入到頁面的data中
3、當監(jiān)聽到redux中數(shù)據(jù)變化時,更新頁面data,從而實現(xiàn)頁面UI刷新
4、模擬mapDispatch方法,為頁面提供修改store數(shù)據(jù)的方法
復制代碼

pageW.js:

const { store } = require('../redux/index');

const initPage = (params = {}, connect = []) => {
  const { 
    onLoad = ()=>{},
    onShow = ()=>{},
    onHide = ()=>{},
    onUnload = ()=>{},
    data = http://www.wxapp-union.com/{}
   } = params;

  const newPage = {
    ...params,
    // ----------------
    OnLoad(...p) {
      onLoad.bind(this)(...p);
    },
    OnShow(...p) {
      onShow.bind(this)(...p);
    },
    OnHide(...p) {
      onHide.bind(this)(...p);
    },
    OnUnload(...p) {
      onUnload.bind(this)(...p);
    },
    // ----------------
    // 清空監(jiān)聽
    clearStoreSubscribe() {
      if (this.storeSubscribe) {
        this.storeSubscribe();
        this.storeSubscribe = undefined;
      }
    },
    // 獲取redux 中 data
    getNewData() {
      const newItems = {};

      const state = this.$store.getState();

      if (connect) {
        if ( Array.isArray(connect) ) {
          connect.forEach((key) => {
            const value = state[key];
            if (value && this.data[key] !== value) {
              newItems[key] = value
            }
          })
        } else if (typeof connect ==='function') {
          const list = connect(state) || {};
          Object.keys(list).forEach((key) => {
            const value = list[key];
            if (value && this.data[key] !== value) {
              newItems[key] = value
            }
          })
        }
      }

      return newItems;
    },
    // 監(jiān)聽 redux 變化
    handleReduxChange() {
      this.setData({
        ...this.getNewData(),
      });
    },
    // ----------------
    data: {
      ...data
    },
    onLoad(...p) {
      const app = getApp()
      this.$store = app.globalData.$store;
      this.setData({
        ...this.getNewData(),
      });

      this.OnLoad(...p);

      this._isOnLoad = true;
    },
    onShow (...p) {
      if (!this.storeSubscribe) {
        this.storeSubscribe = this.$store.subscribe(()=>this.handleReduxChange());
      }

      if (!this._isOnLoad) {
        this.setData({
          ...this.getNewData(),
        });
      }


      this.OnShow(...p);

      this._isOnLoad = false;
    },
    onHide(...p) {
      this.OnHide(...p);

      this.clearStoreSubscribe();
    },
    onUnload(...p) {
      this.OnUnload(...p);

      this.clearStoreSubscribe();
    },
    // ----------------
    dispatch(...p) {
      if (this.$store) {
        return this.$store.dispatch(...p);
      }
    }
  }

  return newPage;
}

const PageW = (params = {}, mapState = [], mapDispatch = ()=>{}) => {
  const page = initPage({...params}, mapState);
  const dispatchList = mapDispatch(store) || {};

  page.mapDispatch = {
    ...dispatchList
  };

  return Page(page);
}

module.exports = PageW;

復制代碼

PageW 中主要考慮和不足 如下問題:

1、為了保持微信小程序原有生命周名稱不變,所以事先劫持了傳入頁面的生命周期,然后用bind重新在對應生命周期完成后觸發(fā)。
2、因為redux更新數(shù)據(jù),都會生成一個新的數(shù)據(jù)對象,所以每當監(jiān)聽到數(shù)據(jù)變化,新數(shù)據(jù)和老數(shù)據(jù)會進行對比,每次setData,只放入確實發(fā)生變化的數(shù)據(jù)
3、頁面中的data,既維護了默認頁面創(chuàng)建的data數(shù)據(jù),又加入了redux connect 后的數(shù)據(jù),但是目前沒有對這個兩個數(shù)據(jù)的命名進行安全的區(qū)分,所以頁面原生data中的數(shù)據(jù)名稱必須與 connect 注入的數(shù)據(jù)不同。
復制代碼

測試頁面:

導入了testItem, testItem2兩個數(shù)據(jù),導入了add2一個方法

const PageW = require('../../pageW/index');
const { ActionsFun } = require('../../redux/testItem/actions');

const page = {
  data: {
    wwj: 4
  },
  onLoad() {
    console.log('sub onLoad');
  },
  onShow() {

  },
  toTest() {
    console.log('toTest');
    wx.navigateTo({
      url: '/pages/test/index'
    })
  },
  button1() {
    console.log('button1');
    this.mapDispatch.add2();
  },
  button2() {
    const { wwj } = this.data;
    this.setData({
      wwj: wwj + 2
    });
  },
}

const mapState = [ 'testItem', 'testItem2' ];

const mapDispatch = ({dispatch}) => {
  return {
    add2: (params) => dispatch(ActionsFun.add(params))
  }
}

PageW(page, mapState, mapDispatch);

相關(guān)案例查看更多