前言
這篇文章是之前我發表在CSDN上邊的,最近搬到簡書
文件目錄
*---store // 存放redux,數據,以及action
*---store子目錄
actions // 存放action的文件夾
reducers // 存放reducer的文件夾
actionTypes.js // 存放所有的actionType
index.js // store的入口文件
安裝
npm install redux react-redux -S
cnpm install redux react-redux -S
yarn add redux react-redux -S
使用
- 先在index.js中引入react-redux定義的Provider組件,并包裹在App組件外部
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
ReactDOM.render(
<Provider>
<App />
</Provider>,
document.getElementById('root')
);
- 接著在store目錄下的index.js中創建一個store,并拋出
import { createStore, combineReducers } from 'redux';
// createStore方法是用來創建store的,combineReducers方法是用來合并多個reducer的
// 創建根reducer,利用combineReducers合并多個reducer,此處還未定義reducer,所以暫空
const rootReducer = combineReducers({
})
// 創建初始化的state,初始化為一個空對象即可,默認的數據建議都寫在reducer上
const initializeState = {}; // 定義初始化的state
// 創建store,第一個參數是根reducer,第二個參數可以是初始化的state,也可以是別的,暫且不提
const store = createStore(rootReducer,initializeState);
// 拋出store
export default store;
- 在src/index.js中引入store,并且在Provider組件上使用
/**之前的代碼**/
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
- 接著可以先定義數據,即定義reducer,在src/store/reducers目錄下,新建reducer,例如countReducer.js
// 定義初始化的數據,根據實際數據即可
const initializeState = {
count: 1
}
// 定義reducer,第一個參數為state,賦予默認值為上邊定義的initializeState,
// 第二個參數為action,并return一個state
// 并且拋出這個countReducer
export default function countReducer(state = initializeState,action) {
return state;
}
- 在src/store/index.js中引入定義的countReducer,并合并到rootReducer中
// 引入countReducer,
import countReducer from './reducers/countReducer';
// 將countReducer合并到rootReducer上,并使用原有名稱
const rootReducer = combineReducers({
countReducer
})
// 也可以給countReducer改名,如下,改名成為count
const rootReducer = combineReducers({
count: countReducer
})
接著只需要將組件改造一下,就可以使用reducer上邊的數據了
在src/APP.js中,或者是你需要使用store中數據的組件中,引入react-redux提供的connect方法
import { connect } from 'react-redux';
-
并且在拋出之前,定義獲取數據的方法mapStateToProps
// 定義方法mapStateToProps,參數為state,并且返回一個對象,對象內定義需要獲取的store內的數據, // 由于是使用的countReducer中的數據,所以需要使用state.countReducer.屬性名 function mapStateToProps(state) { return { count: state.countReducer.count } }
接著,在拋出的時候調用connect方法改造當前組件
// connect的第一個參數為數據,即mapStateToProps方法
// 接著在第二個括號內傳入當前需要被改造的組件
export default connect(mapStateToProps)(App);
- 然后,我們在被改造的組件內就可以通過this.props.屬性名獲取store中的數據了,例如我在mapStateToProps方法中返回的是count數據,所以我在App組件中使用this.props.count即可
class App extends Component {
render() {
return (
<div>
{this.props.count}
</div>
);
}
}
獲取到數據之后,接著應該是修改倉庫內的數據
修改數據首先需要定義一個dispatch,在redux中,修改數據必須通過dispatch提交一個action來進行,在src/store/actions目錄下新建countAction.js
在countAction.js中定義addCount方法,并return一個對象,對象上有一個type屬性,這個屬性對應的是一個常量字符串,這個字符串定義在src/store/actionTypes.js中,主要是為了可以公共的管理,因為同一個常量需要在兩個地方使用
// countAction.js
import { ADD_COUNT } from '../actionTypes'
export function addCount() {
return {
type: ADD_COUNT
}
}
// actionTypes.js
export const ADD_COUNT = 'ADD_COUNT';
-
接著在src/store/reducers/countReducer.js中,引入ADD_COUNT常量,并使用switch語句,或者if語句對action.type進行判斷,當觸發這個action的時候,讓當前這個reducer的state.count加一
import { ADD_COUNT } from '../actionTypes'; export default function countReducer(state = initializeState,action) { switch (action.type) { case ADD_COUNT: return { count: state.count + 1 }; default: return state; } }
緊接著,要在組件中使用這個addCount方法,提交這個dispatch,觸發這個action
在App.js或者是使用store的組件中,首先引入addCount方法,然后在mapStateToProps的下邊,在定義一個mapActionToProps方法,接著在connect的第二個參數位置,傳入這個方法即可
-
在mapActionToProps方法中,第一個參數為dispatch,return一個對象,對象上定義方法
方法名自定義即可,接著觸發這個方法的時候,觸發dispatch(),并傳入引入的addCount()方法,需要加括號調用,因為只有調用才會返回一個對象,( 或者addCount直接是一個對象,而不是一個函數 )import { addCount } from './store/actions/countAction' /** 其余代碼 **/ /** mapStateToProps **/ function mapActionToProps(dispatch) { return { addCount: () => dispatch(addCount()) } } export default connect(mapStateToProps,mapActionToProps)(App);
此時,可以在App組件內調用this.props.addCount()方法來修改store中的數據了
當然,但凡是方法,都可以傳參,
首先在src/store/actions/countAction.js中定義一個新的方法,
-
當然,這個方法用到的REDUCE_COUNT常量要定義在src/store/actionTypes.js中
// src/store/actions/countAction.js export function reduceCount(num) { return { type: REDUCE_COUNT, num } } // src/store/actionTypes.js export const REDUCE_COUNT = 'REDUCE_COUNT';
而且,在src/store/reducers/countReducer.js中,需要通過switch進行判斷action,并執行操作
由于我們在action中定義的對象的屬性是num,所以在reducer中進行參數使用的時候,也是使用action.num
// src/store/reducers/countReducer.js
import { ADD_COUNT, REDUCE_COUNT } from '../actionTypes'
export default function countReducer(state = initializeState,action) {
switch (action.type) {
case ADD_COUNT:
return { count: state.count + 1 };
// 新增
case REDUCE_COUNT:
return { count: state.count - action.num };
default:
return state;
}
}
- 在App.js中使用reduceCount方法
import { addCount, reduceCount } from './store/actions/countAction';
/** 其余代碼 **/
/** mapStateToProps **/
function mapActionToProps(dispatch) {
return {
addCount: () => dispatch(addCount()),
reduceCount: (num) => dispatch(reduceCount(num))
}
}
接著在組件中直接調用this.props.reduceCount()方法,并傳入一個參數即可
最后,為了遵循react的規范,我們需要在給組件定義props的時候,規定props的類型
首先在App.js或者使用store的組件中,引入prop-types
然后在文件最末尾,拋出之前,定義所有的props的類型
import PropTypes from 'prop-types';
/** 其余代碼 **/
App.propTypes = {
count: PropTypes.number.isRequired,
addCount: PropTypes.func.isRequired,
reduceCount: PropTypes.func.isRequired
}
最終代碼
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
App.js
import React, {Component} from 'react';
import { connect } from 'react-redux';
import { addCount, reduceCount } from './store/actions/countAction';
import PropTypes from 'prop-types';
class App extends Component {
render() {
return (
<div>
<button onClick={()=>this.props.addCount()}>加1</button>
{this.props.count}
<button onClick={()=>this.props.reduceCount(5)}>減5</button>
</div>
);
}
}
function mapStateToProps(state) {
return {
count: state.countReducer.count
}
}
function mapActionToProps(dispatch) {
return {
addCount: () => dispatch(addCount()),
reduceCount: (num) => dispatch(reduceCount(num))
}
}
App.propTypes = {
count: PropTypes.number.isRequired,
addCount: PropTypes.func.isRequired,
reduceCount: PropTypes.func.isRequired
}
export default connect(mapStateToProps,mapActionToProps)(App);
store/index.js
import { createStore, combineReducers } from 'redux';
import countReducer from './reducers/countReducer';
const rootReducer = combineReducers({
countReducer
})
const initializeState = {}; // 定義初始化的state
const store = createStore(rootReducer,initializeState);
export default store;
store/actionTypes.js
export const ADD_COUNT = 'ADD_COUNT';
export const REDUCE_COUNT = 'REDUCE_COUNT';
store/reducers/countReducer.js
import { ADD_COUNT, REDUCE_COUNT } from '../actionTypes'
const initializeState = {
count: 1
}
export default function countReducer(state = initializeState,action) {
switch (action.type) {
case ADD_COUNT:
return { count: state.count + 1 };
case REDUCE_COUNT:
return { count: state.count - action.num };
default:
return state;
}
}
store/actions/countAction.js
import { ADD_COUNT, REDUCE_COUNT } from '../actionTypes'
export function addCount() {
return {
type: ADD_COUNT
}
}
export function reduceCount(num) {
return {
type: REDUCE_COUNT,
num
}
}
- 如果需要使用中間件的話
- 在store/index.js中,引入applyMiddleware,并使用在createStore的第三個參數位置
- 接著引入需要使用的中間件,比如redux-thunk
- 定義一個數組,用來存放所有的中間件
- 在applyMiddleware方法中展開該數組即可
import { createStore, combineReducers, applyMiddleware } from 'redux';
// 引入redux-thunk
import thunk from 'redux-thunk';
// 定義中間件的數組
const middleware = [ thunk ]
// 使用
const store = createStore(rootReducer,initializeState,applyMiddleware(...middleware));