React進階(九):React-Redux

      網友投稿 878 2025-04-01

      前言


      React-Redux 將所有組件分成兩大類:UI 組件(presentational component)和容器組件(container component)。

      UI組件

      只負責 UI 的呈現,不帶有任何業務邏輯;

      沒有狀態(即不使用this.state這個變量);

      所有數據都由參數(this.props)提供;

      不使用任何 Redux 的 API;

      容器組件

      負責管理數據和業務邏輯,不負責 UI 呈現;

      帶有內部狀態;

      使用 Redux 的 API;

      UI 組件負責 UI 的呈現,容器組件負責管理數據和邏輯。

      如果一個組件既有 UI 又有業務邏輯,那怎么辦?回答是,將它拆分成下面的結構:外面是一個容器組件,里面包了一個UI 組件。前者負責與外部的通信,將數據傳給后者,由后者渲染出視圖。

      React-Redux 規定,所有的 UI 組件都由用戶提供,容器組件則是由 React-Redux 自動生成。也就是說,用戶負責視覺層,狀態管理則是全部交給它。

      connect()

      React-Redux 提供connect方法,用于從 UI 組件生成容器組件。connect的意思就是將這兩種組件連起來。

      import { connect } from 'react-redux' const VisibleTodoList = connect()(TodoList);

      1

      2

      上面VisibleTodoList 便是通過connect方法自動生成的容器組件。

      但需要定義業務邏輯,組件才有意義。

      import { connect } from 'react-redux' const VisibleTodoList = connect( mapStateToProps, mapDispatchToProps )(TodoList)

      1

      2

      3

      4

      5

      connect方法接受兩個參數:mapStateToProps和mapDispatchToProps。它們定義了 UI 組件的業務邏輯。前者負責輸入邏輯,即將state映射到 UI 組件的參數(props),后者負責輸出邏輯,即將用戶對 UI 組件的操作映射成 Action。

      mapStateToProps()

      它是一個函數,建立一個從(外部的)state對象到(UI 組件的)props對象的映射關系。

      mapStateToProps執行后應該返回一個對象,里面的每一個鍵值對就是一個映射。

      const mapStateToProps = (state) => { return { todos: getVisibleTodos(state.todos, state.visibilityFilter) } }

      1

      2

      3

      4

      5

      正如前面所說,mapStateToProps是一個函數,它接受state作為參數,返回一個對象。這個對象有一個todos屬性,代表 UI 組件的同名參數,后面的getVisibleTodos也是一個函數,可以從state算出 todos 的值。

      mapDispatchToProps()

      mapDispatchToProps是connect函數的第二個參數,用來建立 UI 組件的參數到store.dispatch方法的映射。它定義了哪些用戶的操作應該當作 Action,傳給 Store。它可以是一個函數,也可以是一個對象。

      當mapDispatchToProps為函數時,則會得到dispatch和ownProps(容器組件的props對象)兩個參數。

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

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      從上面代碼可以看到,mapDispatchToProps作為函數,應該返回一個對象,該對象的每個鍵值對都是一個映射,定義了 UI 組件的參數怎樣發出 Action。

      當mapDispatchToProps為對象時,它的每個鍵名也是對應 UI 組件的同名參數,鍵值應該是一個函數,會被當作 Action creator ,返回的 Action 會由 Redux 自動發出。

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

      1

      2

      3

      4

      5

      6

      組件

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

      React-Redux 提供Provider組件,可以讓容器組件拿到state。

      import { Provider } from 'react-redux' import { createStore } from 'redux' import todoApp from './reducers' import App from './components/App' let store = createStore(todoApp); render( , document.getElementById('root') )

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      上面代碼中,Provider在根組件外面包了一層,這樣一來,App的所有子組件就默認都可以拿到state了。

      Demo:簡單計數器

      下面是一個計數器組件,它是一個純的 UI 組件。

      class Counter extends Component { render() { const { value, onIncreaseClick } = this.props return (

      {value}
      ) } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      上面代碼中,這個 UI 組件有兩個參數:value和onIncreaseClick。前者需要從state計算得到,后者需要向外發出 Action。

      接著,定義value到state的映射,以及onIncreaseClick到dispatch的映射。

      function mapStateToProps(state) { return { value: state.count } } function mapDispatchToProps(dispatch) { return { onIncreaseClick: () => dispatch(increaseAction) } } // Action Creator const increaseAction = { type: 'increase' }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      然后,使用connect方法生成容器組件。

      const App = connect( mapStateToProps, mapDispatchToProps )(Counter)

      1

      2

      3

      4

      然后,定義這個組件的 Reducer。

      // Reducer function counter(state = { count: 0 }, action) { const count = state.count switch (action.type) { case 'increase': return { count: count + 1 } default: return state } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      最后,生成store對象,并使用Provider在根組件外面包一層。

      import { loadState, saveState } from './localStorage'; const persistedState = loadState(); const store = createStore( todoApp, persistedState ); store.subscribe(throttle(() => { saveState({ todos: store.getState().todos, }) }, 1000)) ReactDOM.render( , document.getElementById('root') );

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      完整代碼如下:

      import React, { Component } from 'react' import PropTypes from 'prop-types' //類型檢查 import ReactDOM from 'react-dom' import { createStore } from 'redux' import { Provider, connect } from 'react-redux' // 定義counter組件 class Counter extends Component { render() { const { value, onIncreaseClick } = this.props // const value = this.props.value return (

      {value}
      ) } } //對Counter組件接受的props進行類型檢查 Counter.propTypes = { value: PropTypes.number.isRequired, //要求數字類型,沒有提供會警告 onIncreaseClick: PropTypes.func.isRequired //要求函數類型 } // Action const increaseAction = { type: 'increase' } // Reducer基于原有state,根據action得到新的state function counter(state = { count: 0 }, action) { const count = state.count switch (action.type) { case 'increase': return { count: count + 1 } default: return state } } // 根據reducer函數通過createStore()創建store const store = createStore(counter) // 將state映射到Counter組件的props function mapStateToProps(state) { return { value: state.count } } // 將action映射到Counter組件的props function mapDispatchToProps(dispatch) { return { onIncreaseClick: () => dispatch(increaseAction) } } // 傳入上面兩個函數參數,將Counter組件變為App組件 const App = connect( mapStateToProps, mapDispatchToProps )(Counter) ReactDOM.render( , document.getElementById('root') )

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      React進階(九):React-Redux

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      拓展閱讀

      React Redux文檔

      React Redux 容器

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:Kafka停機,如何無感知遷移ZooKeeper集群?
      下一篇:如何用excel畫曲線圖的教程
      相關文章
      久久精品国产亚洲7777| 久久夜色精品国产亚洲AV动态图 | 亚洲精品国产成人| 亚洲欧洲第一a在线观看| 亚洲一区二区三区无码影院| 日韩色日韩视频亚洲网站| 亚洲欧美日韩中文字幕一区二区三区| 亚洲乱码无限2021芒果| 亚洲日产2021三区| 亚洲人成在线中文字幕| 亚洲午夜精品在线| avtt天堂网手机版亚洲| 亚洲一区二区三区在线网站| 国产成人精品日本亚洲直接 | 国内精品久久久久久久亚洲| 中文亚洲成a人片在线观看| 亚洲国产小视频精品久久久三级| 亚洲高清无在码在线电影不卡| 久久久久久久综合日本亚洲 | 亚洲色偷偷综合亚洲AV伊人| 亚洲中文字幕无码久久精品1 | 亚洲线精品一区二区三区影音先锋| 亚洲av永久无码一区二区三区| 亚洲国产成人精品无码区二本| 亚洲а∨天堂久久精品9966| 亚洲精品永久在线观看| 国产成人亚洲精品| 亚洲人成电影网站色www| 无码一区二区三区亚洲人妻| 亚洲精品国产高清嫩草影院| 国产亚洲美女精品久久久| 国产亚洲精品美女久久久| 亚洲视频在线视频| 亚洲人成电影在线观看青青| 亚洲天然素人无码专区| 午夜在线亚洲男人午在线| 国外亚洲成AV人片在线观看| 亚洲s色大片在线观看| 亚洲黄色一级毛片| 国产亚洲精品VA片在线播放| 日本系列1页亚洲系列|