redux介紹與入門

1、什麼是flux

  1.redux的設計思想與flux是差很少同樣的,因此咱們先來了解什麼fluxreact

  2.flux是一種設計模式或者說是框架。以mvc模式來劃分的話react是mvc中的view, flux至關於mc,m就是model c就是control。那麼咱們就明白flux究竟是什麼了,看下圖: ios

 

  flux包含四個部分 Store、Dispatch、Action、View,其中Store就對應着model,Dispatch、Action就組合成了Control。這麼劃分僅僅是幫助全局理解flux究竟是什麼。web

  3.flux就是一種設計模式,當view或者用戶產生一個Action時,Dispatch會解析Action根據不一樣的Action修改Store,被修改的Store會發消息通知View說:我已經修改了過來取我並更新你本身吧。npm

  4.一個簡單例子redux

// store
var Store = {
 state:{
  loginData:{
   type:'login',
   data:'no login',
  },
  logoutData:{
   type:'logout',
   data:'',
  }
 },
 login:function(data){
  this.state.loginData = data;
 },
 logout:function(data){
  this.state.logoutData = data;
 },
 getState:function(){
  return this.state;
 },
 sendEvent:function(){
  this.callback();
 },
 addChangeListener: function(callback) {
     this.callback = callback;
   },
   removeChangeListener: function(callback) {
    }
}
 
// Dispatch
var Dispatcher = require('flux').Dispatcher;
var dispatch = new Dispatcher();
dispatch.register(function(payload){
 switch (payload.type){
  case 'login' :
   Store.login(payload);
   Store.sendEvent();
   break;
  case 'logout':
   Store.logout(payload);
   Store.sendEvent();
   break;
 }
});
 
 
// View
Store.addChangeListener(()=>{
 console.log('{\nloginData:{type:'+Store.getState().loginData.type + ' data:' + Store.getState().loginData.data+ '}');
 console.log('logoutData:{type:'+Store.getState().logoutData.type + ' data:' + Store.getState().logoutData.data+ '}\n}');
});
 
 
// Action
var loginAction = { 
 type: 'login',
 data: 'login sucessed'
};
var logoutAction = { 
 type: 'logout',
 data: 'logout sucessed'
};
console.log('登陸....');
dispatch.dispatch(loginAction);
console.log('退出....');
dispatch.dispatch(logoutAction);

2、redux

  1.咱們先看看看官網的一個例子react-native

var Redux = require('redux')
var
createStore = Redux.createStore function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } }
// 建立store let store
= createStore(counter) store.subscribe(() => console.log(store.getState()) ) store.dispatch({ type: 'INCREMENT' }) // 1 store.dispatch({ type: 'INCREMENT' }) // 2 store.dispatch({ type: 'DECREMENT' }) // 1

  能夠看到redux與flux原理是同樣的,只是實現不同。設計模式

  1.redux把dispatch封裝到了Store裏xcode

// 因此咱們能夠直接經過store來發送dispatch
store.dispatch({ type: 'INCREMENT' })

  2.抽象出一個reducer概念(counter就是一個reducer),reducer就是一個[根據不一樣的dispatch處理並生產新的state的一個程序]。mvc

// 處理自增、或者自減的程序
function counter(state = 0, action) {
  switch (action.type) {
  case 'INCREMENT':
    return state + 1
  case 'DECREMENT':
    return state - 1
  default:
    return state
  }
}

  要理解redux,其實就是要理解Redux提供的Store與reducer。 app

3、react中使用redux

  咱們將會重頭建立一個React-native項目,而後加入redux框架 

#初始化一個react-native項目
$ react-native init reduxTest
$ cd reduxTest/ios
$ open reduxTest.xcodeproj
#這樣就建立並打開了一個iOS的react-native項目

  1.添加app.js

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableHighlight
} from 'react-native';
class App extends Component {
  onPress(){

  }
  render() {
    let welcome = this.props.appInfo?this.props.appInfo.welcome:'Welcome to Redux test!'
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          {welcome}
        </Text>
        <TouchableHighlight onPress={this.onPress.bind(this)}>
          <Text >
            Click me!
          </Text>
        </TouchableHighlight>
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});
module.exports = App;

  2.修改reduxTest/index.ios.js

import React, { Component } from 'react';
import {
  AppRegistry,
} from 'react-native';
import App from './app'
export default class reduxTest extends Component {
  render() {
    return (
      <App></App>
    );
  }
}
AppRegistry.registerComponent('reduxTest', () => reduxTest);

  這時候咱們獲得一個簡單的測試app,下面我經過redux來管理app組件的state(redux把state映射到props)。

  效果:當點擊Click me! 按鈕時,會吧welcome信息改成 have clicked!

  具體流程就是:

  (1).點擊 Click me! 按鈕 ,會經過redux的Store發送一個dispatch給reducer,reducer把welcome改成‘have clicked’

  (2).而後redux會通知app 組件從新渲染

  3.安裝redux、react-redux、redux-thunk

$ npm install redux --save 
$ npm install react-redux --save
$ npm install redux-thunk --save

  3.直接上源碼,代碼後面有解釋

  總共涉及4個文件,須要重點關注的代碼將會被標紅

  • index.ios.js --  建立store 
  • app.js      --  根據store的改變作出相應的處理、用戶點擊時發出action
  • reducer.js    --  處理action 
  • action.js      --  具體的action

  index.ios.js:

import React, { Component } from 'react';
import {
  AppRegistry,
} from 'react-native';

import App from './app'
import appReducer           from './reducer'

import {createStore,
  applyMiddleware}        from 'redux';
import {Provider}           from 'react-redux';
import thunk                from 'redux-thunk';

let store = createStore(appReducer,
  applyMiddleware(thunk)              // 用於異步的action
); 
export default class reduxTest extends Component {
  render() {
    return (
      <Provider store={store}>
        <App></App>
      </Provider>

    );
  }
}
AppRegistry.registerComponent('reduxTest', () => reduxTest);

  解析

  這裏引入了四個redux相關組件

  • createStore        --- 是一個函數,用於建立store
  • applyMiddleware    --- 是一個函數,用於使用中間件
  • hunk                     --- 是一個函數,是中間件用於使action函數支持異步;
  • Provider                --- 是一個react組件,主要提供一個全局的store使得它的子組件都能訪問到

  建立store的代碼:

let store = createStore(
    appReducer,
    applyMiddleware(thunk)     // 用於異步的action
);
/**
    @appReducer :是一個reducer,咱們說過是用於處理action的。
    @applyMiddleware(thunk) : 應用一個叫thunk的中間件,任何一個action執行前會先執行thunk

    這裏咱們應該記住:
    store提供一個保存state的地方
    store也提供了一個發出dispatch的方法
    store也提供了一個監聽state的方法  
*/

  Provider:Provider是提供者,意思就是給他的子組件提供一個store,這個store就是咱們上面建立的。

  app.js:

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableHighlight
} from 'react-native';
import {connect} from 'react-redux';
import {bindActionCreators}  from 'redux';

import WelcomeAction from './action'

class App extends Component {
  // 定義 上線文裏store屬性的類型爲object
  static contextTypes = { store: React.PropTypes.object }
  componentDidMount() {
    // store的做用1: 監聽state的變化
    const { store } = this.context;
    store.subscribe(
      ()=>{
        // store的做用2: 獲取state
        let state = store.getState();
        // state改變了
        console.log('state:',state); } );
  }
  onPress(){
    // 1.直接用store發生dipatch
    let action = {
      type:'welcome',
      data:{
        text:'have clicked from app.js',
      }
    }
    // store的做用3: 發送dispatch
    this.context.store.dispatch(action)
    
    // this.props.onPressAction()
  }
  render() {
    let welcome = this.props.welcome
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          {welcome}
        </Text>
        <TouchableHighlight onPress={this.onPress.bind(this)}>
          <Text >
            Click me!
          </Text>
        </TouchableHighlight>
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});
function mapStateToProps(state) {
  return {
    welcome: state.welcome
  }
}
function mapDispatchToProps(dispatch) {
  return {
    onPressAction:bindActionCreators(WelcomeAction,dispatch),
  }
}
module.exports = connect(mapStateToProps,mapDispatchToProps)(App);

  解析

 (1)獲取store

  由於app組件是Provider組件的子組件,因此app組件跟Provider組件是共享一個context(上下文)的 --- 這個是react的規定,不瞭解的請自行補相應知識。

  只要在app組件定義一下store的類型就能使用了

// 定義 上線文裏store屬性的類型爲object
  static contextTypes = {
    store: React.PropTypes.object
  }
// 經過下面就能獲取到store
this.context.store

  這個store是與建立Provider時傳入的store是同一個

<Provider store={store}>
    <App></App>
</Provider>

 (2)使用store

  獲取到store以後咱們就能夠用於發送dispatch、監聽state了

  發送dispatch:

    let action = {
      type:'welcome',
      data:{
        text:'have clicked from app.js',
      }
    }
    // store的做用3: 發送dispatch
    this.context.store.dispatch(action)

    action參數是一個對象,對象結構沒有作要求。

  action被dispatch以後會被reducer處理,處理完後就會發一個通知說state已經更新了。

  經過下面代碼來監聽通知

// store的做用1: 監聽state的變化
    const { store } = this.context;
    store.subscribe(
      ()=>{
        // store的做用2: 獲取state
        let state = store.getState();
        // state改變了
        // 根據state作相應的渲染
        console.log('state:',state);
      }
    );

 我看下面的reducer是怎麼處理action的

 reducer.js:

function Reducer(state = {welcome:'Welcome to Redux test!'}, action) {
  switch (action.type) {
    case 'welcome':
      return {welcome:action.data.text};
    default:
      return state
  }
}
module.exports = Reducer;

  解析:

  很簡單的處理,若是action的type等於‘welcome’的話,就直接返回一個對象{welcome:action.data.text};

  監聽者收到的就是這個返回的對象。

  值得注意,Reducer的參數 state = {welcome:'Welcome to Redux test!'},是state的默認值

---------------------------------------------------------------------

 

  每次都經過this.context.sotre來dispatch、subscribe,你們都以爲很煩,好吧redux已經作了封裝:

  引入兩個組件:

  • connect   ----  用於封裝App組件
  • bindActionCreators   --- 綁定action的構造者

  具體使用:

function mapStateToProps(state) {
  return {
    welcome: state.welcome
  }
}
function mapDispatchToProps(dispatch) {
  return {
    onPressAction:bindActionCreators(WelcomeAction,dispatch),
  }
}

module.exports = connect(mapStateToProps,mapDispatchToProps)(App);

  解析:

  function mapStateToProps(state)

  正如函數名所表示,它的做用就是把state映射到props上。這裏的state是指store保存的state,props是指app組件的props。

  這個函數須要返回一個對象

return {
    welcome: state.welcome
  }

  而後經過connect組件封裝一下

module.exports = connect(mapStateToProps,mapDispatchToProps)(App);

  這樣子,在app組件內部就能經過this.props.welcome來獲取store保存的state對應的welcome的值了,是否是分方便?

  既然state能映射到props,那麼dispatch action也能映射

 
 
import WelcomeAction from './action'

function
mapDispatchToProps(dispatch) { return { onPressAction:bindActionCreators(WelcomeAction,dispatch), } } module.exports = connect(mapStateToProps,mapDispatchToProps)(App);

  上面的代碼意思就是吧dispatch映射到props上,dispatch是sotre的dispatch,props是app的props.

  咱們能夠這樣直接發出一個action,

this.props.onPressAction()

  onPressaction()等同於  WelcomeAction

  WelcomeAction是什麼請看往下看:

  action.js:

function WelcomeAction () {
  // 異步
  return (dipatch, getState) => {
    return new Promise((resolve,reject)=>{
      setTimeout(()=>{
        let action = {
          type:'welcome',
          data:{
            text:'have clicked??',
          }
        }
        dipatch(action);         resolve();
      },2000);
    });
  }
  // 同步
  // return {
  //   type:'welcome',
  //   data:{
  //     text:'have clicked',
  //   }
  // }
}
module.exports = WelcomeAction   

  WelcomeAction函數用到dispatch等於store.dispatch

   這樣作的目的是把action獨立出來方便單獨管理。

  action函數,若是須要異步執行就返回一個Promise,同步執行能夠直接返回一個新的state  

  值得注意若是action函數須要異步執行,在建立store的時候必須使用中間件trunk

 

import thunk                from 'redux-thunk';

let store = createStore( appReducer, applyMiddleware(thunk) // 用於異步的action );
相關文章
相關標籤/搜索