如何優雅地在React項目中使用Redux


前言

或許你當前的項目還沒有到應用Redux的程度,但提前了解一下也沒有壞處,本文不會安利大家使用Redux

概念

首先我們會用到哪些框架和工具呢?

React

UI框架

Redux

狀態管理工具,與React沒有任何關系,其他UI框架也可以使用Redux

react-redux

React插件,作用:方便在React項目中使用Redux

react-thunk

中間件,作用:支持異步action

目錄結構

Tips:與Redux無關的目錄已省略

 

1 |--src
2     |-- store                Redux目錄
3         |-- actions.js
4         |-- index.js
5         |-- reducers.js
6         |-- state.js
7     |-- components         組件目錄
8         |-- Test.jsx
9     |-- App.js               項目入口

 

准備工作

第1步:提供默認值,既然用Redux來管理數據,那么數據就一定要有默認值,所以我們將state的默認值統一放置在state.js文件

 1 // state.js
 2 
 3 // 聲明默認值
 4 // 這里我們列舉兩個示例
 5 // 同步數據:pageTitle
 6 // 異步數據:infoList(將來用異步接口獲取)
 7 export default {
 8     pageTitle: '首頁',
 9     infoList: []
10 }  

 

第2步:創建reducer,它就是將來真正要用到的數據,我們將其統一放置在reducers.js文件

 1 // reducers.js
 2 
 3 // 工具函數,用於組織多個reducer,並返回reducer集合
 4 import { combineReducers } from 'redux'
 5 // 默認值
 6 import defaultState from './state.js'
 7 
 8 // 一個reducer就是一個函數
 9 function pageTitle (state = defaultState.pageTitle, action) {
10   // 不同的action有不同的處理邏輯
11   switch (action.type) {
12     case 'SET_PAGE_TITLE':
13       return action.data
14     default:
15       return state
16   }
17 }
18 
19 function infoList (state = defaultState.infoList, action) {
20   switch (action.type) {
21     case 'SET_INFO_LIST':
22       return action.data
23     default:
24       return state
25   }
26 }
27 
28 // 導出所有reducer
29 export default combineReducers({
30     pageTitle,
31     infoList
32 })

 

第3步:創建action,現在我們已經創建了reducer,但是還沒有對應的action來操作它們,所以接下來就來編寫action

 1 // actions.js
 2 
 3 // action也是函數
 4 export function setPageTitle (data) {
 5   return (dispatch, getState) => {
 6     dispatch({ type: 'SET_PAGE_TITLE', data: data })
 7   }
 8 }
 9 
10 export function setInfoList (data) {
11   return (dispatch, getState) => {
12     // 使用fetch實現異步請求
13     window.fetch('/api/getInfoList', {
14         method: 'GET',
15         headers: {
16             'Content-Type': 'application/json'
17         }
18     }).then(res => {
19         return res.json()
20     }).then(data => {
21         let { code, data } = data
22         if (code === 0) {
23             dispatch({ type: 'SET_INFO_LIST', data: data })
24         }
25     })
26   }
27 }

 

最后一步:創建store實例

 1 // index.js
 2 
 3 // applyMiddleware: redux通過該函數來使用中間件
 4 // createStore: 用於創建store實例
 5 import { applyMiddleware, createStore } from 'redux'
 6 
 7 // 中間件,作用:如果不使用該中間件,當我們dispatch一個action時,需要給dispatch函數傳入action對象;但如果我們使用了這個中間件,那么就可以傳入一個函數,這個函數接收兩個參數:dispatch和getState。這個dispatch可以在將來的異步請求完成后使用,對於異步action很有用
 8 import thunk from 'redux-thunk'
 9 
10 // 引入reducer
11 import reducers from './reducers.js'
12 
13 // 創建store實例
14 let store = createStore(
15   reducers,
16   applyMiddleware(thunk)
17 )
18 
19 export default store

 

至此,我們已經完成了所有使用Redux的准備工作,接下來就在React組件中使用Redux

開始使用

首先,我們來編寫應用的入口文件APP.js

 1 // App.js
 2 
 3 import React from 'react'
 4 import ReactDOM from 'react-dom'
 5 
 6 // 引入組件
 7 import TestComponent from './components/Test.jsx'
 8 
 9 // Provider是react-redux兩個核心工具之一,作用:將store傳遞到每個項目中的組件中
10 // 第二個工具是connect,稍后會作介紹
11 import { Provider } from 'react-redux'
12 // 引入創建好的store實例
13 import store from '@/store/index.js'
14 
15 // 渲染DOM
16 ReactDOM.render (
17   (
18     <div>
19         {/* 將store作為prop傳入,即可使應用中的所有組件使用store */}
20         <Provider store = {store}>
21           <TestComponent />
22         </Provider>
23     </div>
24   ),
25   document.getElementById('root')
26 )

 

最后是我們的組件:Test.jsx

 1 // Test.jsx
 2 
 3 import React, { Component } from 'react'
 4 
 5 // connect方法的作用:將額外的props傳遞給組件,並返回新的組件,組件在該過程中不會受到影響
 6 import { connect } from 'react-redux'
 7 
 8 // 引入action
 9 import { setPageTitle, setInfoList } from '../store/actions.js'
10 
11 class Test extends Component {
12   constructor(props) {
13     super(props)
14   }
15 
16   componentDidMount () {
17     let { setPageTitle, setInfoList } = this.props
18     
19     // 觸發setPageTitle action
20     setPageTitle('新的標題')
21     
22     // 觸發setInfoList action
23     setInfoList()
24   }
25 
26   render () {
27     // 從props中解構store
28     let { pageTitle, infoList } = this.props
29     
30     // 使用store
31     return (
32       <div>
33         <h1>{pageTitle}</h1>
34         {
35             infoList.length > 0 ? (
36                 <ul>
37                     {
38                         infoList.map((item, index) => {
39                             <li>{item.data}</li>
40                         })
41                     }
42                 </ul>
43             ):null
44         }
45       </div>
46     )
47   }
48 }
49 
50 // mapStateToProps:將state映射到組件的props中
51 const mapStateToProps = (state) => {
52   return {
53     pageTitle: state.pageTitle,
54     infoList: state.infoList
55   }
56 }
57 
58 // mapDispatchToProps:將dispatch映射到組件的props中
59 const mapDispatchToProps = (dispatch, ownProps) => {
60   return {
61     setPageTitle (data) {
62         // 如果不懂這里的邏輯可查看前面對redux-thunk的介紹
63         dispatch(setPageTitle(data))
64         // 執行setPageTitle會返回一個函數
65         // 這正是redux-thunk的所用之處:異步action
66         // 上行代碼相當於
67         /*dispatch((dispatch, getState) => {
68             dispatch({ type: 'SET_PAGE_TITLE', data: data })
69         )*/
70     },
71     setInfoList (data) {
72         dispatch(setInfoList(data))
73     }
74   }
75 }
76 
77 export default connect(mapStateToProps, mapDispatchToProps)(Test)

 

Redux三大原則

  • 單一數據源
    整個應用的 state 被儲存在一棵 object tree 中,並且這個 object tree 只存在於唯一一個 store 中
  • State 是只讀的
    唯一改變 state 的方法就是觸發 action,action 是一個用於描述已發生事件的普通對象
  • 使用純函數來執行修改
    為了描述 action 如何改變 state tree ,你需要編寫 reducers

結語

以上就是在React項目中使用Redux的簡單示例,文中代碼可能會有編寫錯誤,歡迎指正,同事希望本文對大家有所幫助

參考

 

 

原文出處:如何優雅地在React項目中使用Redux


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM