前言
这篇文章是之前我发表在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));
网友评论