[React] 13 - Redux: react-redux

Ref: Redux 入門教程(三):React-Redux 的用法html

 

組件拆分規範


使用 React-Redux,須要掌握額外的 API,而且要遵照它的組件拆分規範react

 

React-Redux 將全部組件分紅兩大類:git

  • UI 組件 負責 UI 的呈現,就是conponent。
  • 容器組件 負責管理數據和邏輯,就是container。

若是一個組件既有 UI 又有業務邏輯,那怎麼辦?github

將它拆分紅下面的結構:redux

 * 外面是一個容器組件,    ----> 前者負責與外部的通訊,將數據傳給後者  ----> 由 React-Redux 自動生成閉包

 * 裏面包了一個UI 組件。      ----> 後者渲染出視圖                                         ----> 由用戶提供框架

 

 

 

connect函數


1、 UI 組件 --> 容器組件

connect方法,用於從 UI 組件生成容器組件connect的意思,就是將這兩種組件連起來。less

import { connect } from 'react-redux'

const VisibleTodoList【容器組件】 = connect(mapStateToProps, mapDispatchToProps)(TodoList【UI組件】)
  • 代碼解析

(1) 一個頁面可能會有十個state,使用connect讓咱們只關注當前有使用的幾個ide

(2) 尾部的參數的意思:由於返回的是一個帶參數的func,參見: js 用閉包實現 curry化函數

   

 

 

2、connect的兩個參數

  • mapStateToProps

創建一個從 (外部的)state對象 到(UI 組件的)props對象 的映射關係。

 

    • 第一個參數,老是state對象
/**
* 參數state表明的是 整個網頁的「狀態」。
*/
const mapStateToProps = (state) => { return { todos: getVisibleTodos(state.todos, state.visibilityFilter)    // 從算出  的值 ----> } }
statetodos

state算出 todos 的值。

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_ALL':
      return todos
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
    default:
      throw new Error('Unknown filter: ' + filter)
  }
}

 

    • 第二個參數,表明容器組件的props對象
// 容器組件的代碼
//    <FilterLink filter="SHOW_ALL">
//      All
//    </FilterLink>

const mapStateToProps = (state, ownProps) => {
  return {
    active: ownProps.filter === state.visibilityFilter
  }
}

使用ownProps做爲參數後,若是容器組件的參數發生變化,也會引起 UI 組件從新渲染。

connect方法能夠省略mapStateToProps參數,那樣的話,UI 組件就不會訂閱Store,就是說 Store 的更新不會引發 UI 組件的更新。

 

  • mapDispatchToProps

創建映射:(外部的) state對象 ====>  (UI 組件的) props對象 

創建映射:UI 組件的參數           ====>  store.dispatch方法

定義了哪些用戶的操做應該看成 Action,傳給 Store。

const mapDispatchToProps = (
  dispatch,
  ownProps
) => {
  return {
    onClick: () => {
      dispatch({
        type: 'SET_VISIBILITY_FILTER',
        filter: ownProps.filter
      });
    }
  };
}

 

思考題:有了connect -> react-reduct,就不須要:Every listener registered with store.subscribe(listener) will now be invoked.  

 

 

  

Provider 組件


1、原理

connect方法生成容器組件之後,須要讓容器組件拿到state對象,才能生成 UI 組件的參數。

一種解決方法是將state對象做爲參數,傳入容器組件。可是,這樣作比較麻煩,尤爲是容器組件可能在很深的層級,一級級將state傳下去就很麻煩。

React-Redux 提供Provider組件,可讓容器組件拿到state。其實就是在講下圖。

 

  

2、放在共享位置裏

利用React組件的context屬性,Provider在根組件外面包了一層,這樣一來,App的全部子組件就默認均可以拿到state了。

import { Provider }    from 'react-redux'
import { createStore } from 'redux'
import todoApp         from './reducers'
import App             from './components/App'

let store = createStore(todoApp);

render(  
<Providerstore={store}>  // <----------- 這裏就是重點! <App /> </Provider>,
document.getElementById('root') )

 

3、從共享位置獲取

子組件就能夠從context拿到store

/* 容器組件,visibleTodoList */
class VisibleTodoList extends Component { componentDidMount() { const { store } = this.context; this.unsubscribe = store.subscribe(() => this.forceUpdate() ); } render() { const props = this.props; const { store } = this.context; const state = store.getState(); // ... } } VisibleTodoList.contextTypes = { store: React.PropTypes.object }

 

 

 

實例代碼研究


Ref: jackielii/simplest-redux-example

Ref: redux/examples/counter/

Ref: bbandydd/serverless-client-s3   【看上去將來會有用】

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

Ref: bbandydd/React_Startkit                              【代碼講解】

Ref: [線上讀書會] andy workshop 一天入魂 react-redux【五個小時~】

 

1、效果圖

3

 

 

2、代碼結構

  • Redux組件拆分

從 3:34:05 / 5:14:37 開始講解代碼。

 

  • container 和 component 的區別

 

container更新狀態;從redux's state去取,與redux溝通。

component畫面如何呈現 based on props,不用redux。

 

Jeff: 下圖可見,number & increment放在了」外面「。

 

 

3、代碼分析

  • Step 1. 從Panel開始

 ---> main.js中的標籤<Panel />

 

[container/Panel.js]

 ---> Panel組件的具體實現。

 

 ---> 前者寫起來簡單些。

export default Panel;
import Panel from '../';

export const Number;
import {Number} from 'Panel';

 

  • Step 2. 組件分離

 

  • Step 3. 發送動做信號

 == 先提出一個疑點 ==

原始方式:狀態的改變(onClick事件在panel裏)

Redux方式:狀態的改變要放在action中,也就是,onClick實則在this,props傳來的action中。

 

== 建立動做 ==

視頻講解 - 4:01:40 / 5:14:37  

點擊按鍵,觸發action,只是發了一個信號。以下,發了一個INCREMENT signal.

[actions/counterAction.js]

 

  • Step 4. 接收動做信號

== 執行動做 ==

reducer中去驗證,即:計算新狀態(硬拷貝)。

狀態 object + 負載 object ==> 新的 狀態 object。

[reducers/counterReducer.js]

 

  • Step 5. 建立 store

== 合併動做 ==

建立 store,將總的reducer做爲參數進行了」綁定「

[store/configureStore.js]

 

  • Step 6. 兩種組件的鏈接

視頻講解 - 4:30:46 / 5:14:37

若有沒有這個參數,全部的state就所有給了Panel(contrainer角色)處理;

有這兩個參數,就是」只處理「當前用到的。

export default connect(mapStateToProps, mapDispatchToProps)(Panel);

 

解決什麼問題?

下圖 line 17 爲什麼能方便地直接獲取 」當下所需「 的變量,這即是 connect 的功勞。

 

== 第一個參數 == 

line 31, 表示全部的state。return的就是其中須要用到的。

 

== 第二個參數 ==

line 39,至關於替代了 dispatch(counterAction)

 

  • Step 7. 容器直接得到 store

[main.js]

configureStore 就是 createStore() 的地方。

 

 

4、添加新功能

有了Redux框架,新功能的添加就成了體力活,這也是 Redux 框架的優點和迷人的地方。

 

  • 按鈕UI組件添加

Btn裏這個button set裏,繼續添加一個button。

 

  • 動做信號添加

注意:這裏取代了dispatch(...)方法,爲何能這樣呢?詳見Step 6。

 

  • 狀態更新方法添加

 

  • 使用「按鈕UI組件」處添加

在Panel.js中 (container) 添加對應的使用方式。

相關文章
相關標籤/搜索