如何优雅地在React项目中使用Redux
前言
或許你當(dāng)前的項目還沒有到應(yīng)用Redux的程度,但提前了解一下也沒有壞處,本文不會安利大家使用Redux
概念
首先我們會用到哪些框架和工具呢?
React
UI框架
Redux
狀態(tài)管理工具,與React沒有任何關(guān)系,其他UI框架也可以使用Redux
react-redux
React插件,作用:方便在React項目中使用Redux
react-thunk
中間件,作用:支持異步action
目錄結(jié)構(gòu)
Tips:與Redux無關(guān)的目錄已省略
?
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 項目入口?
準(zhǔn)備工作
第1步:提供默認(rèn)值,既然用Redux來管理數(shù)據(jù),那么數(shù)據(jù)就一定要有默認(rèn)值,所以我們將state的默認(rèn)值統(tǒng)一放置在state.js文件
1 // state.js 2 3 // 聲明默認(rèn)值 4 // 這里我們列舉兩個示例 5 // 同步數(shù)據(jù):pageTitle 6 // 異步數(shù)據(jù):infoList(將來用異步接口獲取) 7 export default { 8 pageTitle: '首頁', 9 infoList: [] 10 }?
第2步:創(chuàng)建reducer,它就是將來真正要用到的數(shù)據(jù),我們將其統(tǒng)一放置在reducers.js文件
1 // reducers.js 2 3 // 工具函數(shù),用于組織多個reducer,并返回reducer集合 4 import { combineReducers } from 'redux' 5 // 默認(rèn)值 6 import defaultState from './state.js' 7 8 // 一個reducer就是一個函數(shù) 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 // 導(dǎo)出所有reducer 29 export default combineReducers({ 30 pageTitle, 31 infoList 32 })?
第3步:創(chuàng)建action,現(xiàn)在我們已經(jīng)創(chuàng)建了reducer,但是還沒有對應(yīng)的action來操作它們,所以接下來就來編寫action
1 // actions.js 2 3 // action也是函數(shù) 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實現(xiàn)異步請求 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 }?
最后一步:創(chuàng)建store實例
1 // index.js 2 3 // applyMiddleware: redux通過該函數(shù)來使用中間件 4 // createStore: 用于創(chuàng)建store實例 5 import { applyMiddleware, createStore } from 'redux' 6 7 // 中間件,作用:如果不使用該中間件,當(dāng)我們dispatch一個action時,需要給dispatch函數(shù)傳入action對象;但如果我們使用了這個中間件,那么就可以傳入一個函數(shù),這個函數(shù)接收兩個參數(shù):dispatch和getState。這個dispatch可以在將來的異步請求完成后使用,對于異步action很有用 8 import thunk from 'redux-thunk' 9 10 // 引入reducer 11 import reducers from './reducers.js' 12 13 // 創(chuàng)建store實例 14 let store = createStore( 15 reducers, 16 applyMiddleware(thunk) 17 ) 18 19 export default store?
至此,我們已經(jīng)完成了所有使用Redux的準(zhǔn)備工作,接下來就在React組件中使用Redux
開始使用
首先,我們來編寫應(yīng)用的入口文件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 // 引入創(chuàng)建好的store實例 13 import store from '@/store/index.js' 14 15 // 渲染DOM 16 ReactDOM.render ( 17 ( 18 <div> 19 {/* 將store作為prop傳入,即可使應(yīng)用中的所有組件使用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 // 觸發(fā)setPageTitle action 20 setPageTitle('新的標(biāo)題') 21 22 // 觸發(fā)setInfoList action 23 setInfoList() 24 } 25 26 render () { 27 // 從props中解構(gòu)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 // 執(zhí)行setPageTitle會返回一個函數(shù) 65 // 這正是redux-thunk的所用之處:異步action 66 // 上行代碼相當(dāng)于 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三大原則
- 單一數(shù)據(jù)源
整個應(yīng)用的 state 被儲存在一棵 object tree 中,并且這個 object tree 只存在于唯一一個 store 中 - State 是只讀的
唯一改變 state 的方法就是觸發(fā) action,action 是一個用于描述已發(fā)生事件的普通對象 - 使用純函數(shù)來執(zhí)行修改
為了描述 action 如何改變 state tree ,你需要編寫 reducers
結(jié)語
以上就是在React項目中使用Redux的簡單示例,文中代碼可能會有編寫錯誤,歡迎指正,同事希望本文對大家有所幫助
參考
- Redux中文文檔
?
?
原文出處:如何優(yōu)雅地在React項目中使用Redux
轉(zhuǎn)載于:https://www.cnblogs.com/sampapa/p/8134086.html
總結(jié)
以上是生活随笔為你收集整理的如何优雅地在React项目中使用Redux的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在iframe框架中全屏不好使的原因
- 下一篇: js基础练习题 二次封装函数