深入理解Redux之Redux Anywhere

Redux作為一個應用狀態(tài)管理工具,自身和應用框架沒有耦合。理論上我們可以將Redux應用到任何應用中,這也是本文標題Redux Anywhere的由來。本文簡單分析React應用中使用Redux的原理,同時整理了如何在微信小程序中使用Redux。

1.React中使用Redux

1.1 使用示例

在React中使用Redux,需要使用React-Redux工具。這一工具為我們提供了兩個組件

  • Provider.js
  • connect.js

當我們在React中使用Redux時,首先將頂層組件用Provider包裹

var store = createStore(reducer);
var Provider = require('react-redux').Provider;
// App 為上層的Component
class App extend React.Component{
  render() {
    return (
      <Provier store={store}>
        <Container />
      </Provider>
    );
  }
}

在組件中,通過connect方法,返回一個被包裹的組件

var connect = require('react-redux').connect;
var actionCreators = require('...');
// MyComponent是與redux無關的組件
var MyComponent = require('...');

function select(state) {
  return {
    count: state.count
  }
}
export default connect(select, actionCreators)(MyComponent)

1.2 原理簡析

Provider主要代碼

export default class Provider extends Component {
  getChildContext() {
    return { store: this.store }
  }

  constructor(props, context) {
    super(props, context)
    this.store = props.store
  }

  render() {
    return Children.only(this.props.children)
  }
}

React中有一個全局的context對象,各級組件間可以通過context通信。

通過Provider代碼可知,這里實際是將Redux store對象綁定到React的context中,以此來把store應用到React中。

下列片段將React 組件用Provider組件包裹,傳入了Redux store,返回一個高階組件。高階組件在渲染時,以包裹的子組件渲染。

<Provier store={store}>
   <Container />
 </Provider>

connect.js主要邏輯

connect是一個高階函數,執(zhí)行connect(select, actionCreators)(MyComponent)時,生產出一個經過包裹的Connect組件,該組件具有如下特點:

  • 通過this.context獲取store
  • props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作為props傳給真正的Component
  • componentDidMount時,添加事件this.store.subscribe(this.handleChange),使得Redux dispatch(action)后,觸發(fā)回調
  • shouldComponentUpdate時判斷是否有避免進行渲染,提升頁面性能,并得到nextState
  • componentWillUnmount時移除注冊的事件this.handleChange
  • 在非生產環(huán)境下,帶有熱重載功能

這里的關鍵點就在于,通過connect包裹的業(yè)務組件,向Redux store注冊了監(jiān)聽器。在Redux流程中,dispatch(action)時,會檢查當前store的監(jiān)聽器并依次觸發(fā),這樣,就將React組件與Redux結合了起來。

connect.js代碼較多,這里不貼出。注釋版代碼可參看 react-redux源碼學習筆記

2.微信小程序中使用Redux

在微信小程序開發(fā)中,有一個全局的app.js,應用其他地方可以通過getApp()獲得其引用。

結合React-Redux經驗,不難想到,可以將Redux store綁定到全局的app.js中

state變更后,如何觸發(fā)視圖的刷新呢?與connect()方法中關鍵點類似,在page.js中,同樣為Redux store注冊監(jiān)聽器。這樣,在dispatch(action)后,觸發(fā)回調,刷新數據,重新渲染視圖

示例如下

// actions.js 
export const changeText = (text) => {
    return { type: 'CHANGE_TEXT', text }
}
// reducers.js
export default {
    myText(state = '', action) {
        switch (action.type) {
            case 'CHANGE_TEXT':
                return action.text
            default:
                return state
        }
    }
}
//app.js中初始化Store,并放在App實例里以方便調用
//app.js
import { createStore, combineReducers } from './lib/redux.min'
import reducers from './reducers'

const Store = createStore(combineReducers(reducers))

App({
  Store,
  onLaunch: function () {
    // ...

//page logs.js
const app = getApp()
const Store = app.Store
const dispatch = Store.dispatch

Page({
  data: {
    foo: ''
  },
  onLoad() {
    this.unsubStore = Store.subscribe(() => {
      const foo = Store.getState().myText
      this.setData({ foo })
    })
  },
  onUnload() {
    this.unsubStore()
  },
   bindBtn() {
      dispatch(changeText('new text'))
  },
})

上述代碼中,當觸發(fā)dispatch(changeText('new text'))時,在Redux store dispatch方法中,會依次觸發(fā)各個監(jiān)聽器,從而完成處理流程。

上述是一個簡單的示例,無法實現React-Redux那樣,通過connect方法對組件的包裝。定制業(yè)務組件關注的state,并根據新舊state判斷是否需要刷新視圖。

這個wechat-weapp-redux 組件,基于React-Redux進行了微信小程序的改造,可以滿足上述需求。

3.Redux Anywhere

至此,我們已經明白了在應用中使用Redux的關鍵點

  • 將store綁定到一個單例全局對象中
  • 業(yè)務組件中注冊監(jiān)聽器,回調中處理數據更新邏輯

理解上述兩點,便可以將Redux應用到任何應用中了。

參考文章

如果覺得有幫助,可以掃描二維碼對我打賞,謝謝

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容