Practice

以下的code大部份來自 Mastering React Native(書)

記得先 $ npm install redux react-redux —save (or $ yarn add redux..)

creating the store

  • 為了從reducer創建store,我們使用redux內的 createStore (這是一個function,傳入reducer,返回object。有提供幾個方法跟store交互)

  • 跟store交互的方法

    • dispatch(action) - 直接向store 發出一個action

    • getState() - 獲取現在app內的整個store state

    • subscribe(for web) - 訂閱store的更新,可參考此sample

redux 為 single store,此 createStore 方法在應用內應該只會被呼叫過一次

只有一個reducer的時候

import { createStore } from 'redux';

const initialState = {
  count: 0
};

const countReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return {
        count: state.count + 1
      };
    case 'DECREMENT':
      return {
        count: state.count - 1
      };
    case 'ZERO':
      return {
        count: 0
      };
    default:
      return state;
  }
}

export default createStore(countReducer);

多個reducer

import { combineReducers, createStore } from 'redux';

//count Reducer
import count from 'reducers/count';
//metadata Reducer
import metadata from 'reducers/metadata';

const reducer = combineReducers({
  count,
  metadata
});

export default createStore(reducer);

使用combineReducers function,將多個小reducer創建成一個大的reducer模塊化reducers。每個reducer的名字都對應到(store)state objec裡該reducer正在管理的key 如上,count由count reducer管理,metadata由metadata reducer管理。

入口

要使用 redux 的component(通常就是整個app的入口)app.js from here

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

import * as reducers from '../reducers';
import CounterApp from './counterApp';

const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const reducer = combineReducers(reducers);
const store = createStoreWithMiddleware(reducer);

export default class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <CounterApp />
      </Provider>
    );
  }
}

Action creators

The component that creates the action will directly dispatch the action to the store

action.js

​ 通常會把INCREMENT和DECREMENT這些type參數用統一寫在另一頁.js內並且宣告為const(因為action & reducer都會需要用到)

const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT’;

export function increment() {
  return {
    type: types.INCREMENT
  };
}

export function decrement() {
  return {
    type: types.DECREMENT
  };
}

要使用action的component => index.js

ps.在此 Counter為自定義的component。 store 為 export store的.js

import React, {Component} from 'react'
import Counter from '../components/counter'
import { increment, decrement } from './src/actions'
import store from './src/store'

export default class CounterApp extends Component {
  render() {
    return (
      <Counter
        value={store.getState()}
        onIncrement={() => store.dispatch(increment())}
        onDecrement={() => store.dispatch(decrement())}
      />
    );
  }
}

React context and providers

在react內父組件(parent component)可以將參數傳遞給子組件(children),也就是props,這被稱作為context。 如果某個元件(element)向該子元件提供了context,無論子元件在樹結構內(tree)多底,都能訪問該參數。 Provider 就是使用此來創建。 通過Provider組建將整個Redux state tree公開給App。 Provider包了整個應用(app),並且context to任何其他在此app內有在監聽的React組件。 react-redux 使用這種模式提供作為context的store給任何需要訪問store的component(此app內的component)。 所以要使用Provider,需要先從react-redux中import,並且給Provider store這個參數。

import React, { Component } from 'react'
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
} from 'react-native'
import { Provider } from 'react-redux'

import store from './src/store'

class Counter extends Component {

  render() {
    return (
      <Provider store={store}>
        ...
      </Provider>
    );
  }
}

AppRegistry.registerComponent('Counter', () => Counter)

Middleware

為了適應異步(asynchronous)操作和其他自定義的操作,Redux提供了middleware結構。 ps.所謂的異步操作,ex.跟server要資料,call Api…等等 In Redux, middleware is injected between the dispatching of an action and its arrival at the reducer. 我們需要將 middleware 透過 applyMiddleware 加進store內。applyMiddleware為 redux 內的一個function 以下為sample code,加入 redux-logger 和 redux-thunk(記得要先install(yarn) redux-logger 和 redux-thunk)

import { createStore, combineReducers, applyMiddleware} from 'redux'
import { createLogger } from 'redux-logger'
import thunk from 'redux-thunk'
import reducers from './reducers'

const logger = createLogger()
const createStoreWithMiddleware = applyMiddleware(logger, thunk)(createStore)
const store = createStoreWithMiddleware(combineReducers(reducers))
export default store

參考

Last updated