7、React的Redux
Redux理解
- 英文文档: https://redux.js.org/
- 中文文档: http://www.redux.org.cn/
- Github: https://github.com/reactjs/redux
- redux 是一个独立专门用于做状态管理的JS 库(不是react 插件库)
- 它可以用在react, angular, vue 等项目中, 但基本与react 配合使用
- 作用: 集中式管理react 应用中多个组件共享的状态
需要Redux时的情景
- 某个组件的状态,需要共享
- 某个状态需要在任何地方都可以拿到
- 一个组件需要改变全局状态
- 一个组件需要改变另一个组件的状态
Redux基本使用
安装
1
yarn add redux
为了更方便的管理
store
,因此新建一个文件夹store
用于专门存放关于store
相关操作的代码store.js
用于写创建stroe对象相关的代码
1
2
3
4
5import { createStore } from 'redux'
import { counter } from './reducers'
// 生成一个store对象
const store = createStore(counter) // 内部第一次调用初始实例
export default storereducers.js
用于编写一些修改状态的方法,返回将状态修改后的结果。这个函数用于与创建store对象时进行关联
1
2
3
4
5
6
7
8
9
10
11
12// 包含reducer函数的模块
import { INCREMENT, DECREMENT } from './actions-types'
export function counter (state = 0, action) {
switch (action.type) {
case INCREMENT:
return state + action.data
case DECREMENT:
return state - action.data
default:
return state
}
}actions-types.js
定义actions的type。
1
2
3// 包含所有actions type的字符串
export const INCREMENT = 'INCREMENT'
export const DECREMENT = 'DECREMENT'actions.js
生成actions对象的函数
1
2
3
4
5
6
7// 包含所有actions creator
import { DECREMENT, INCREMENT } from "./actions-types";
// 增加
export const increment = (number) => ({ type: INCREMENT, data: number })
// 减少
export const decrement = (number) => ({ type: DECREMENT, data: number })
在入口文件使用
1
2
3
4
5
6
7
8
9
10
11import store from './redux/store'
function init () {
ReactDOM.render(
<App store={store} />,
document.getElementById('root')
);
}
init()
store.subscribe(function () {
init()
})在程序文件中调用
1
2
3
4
5
6
7import { increment, decrement } from '../redux/actions'
increment = () => {
// 1. 获取增加的值
const number = this.select.value * 1
// 2. 计算新的count并更新
this.props.store.dispatch(increment(number))
}
react-redux
一个用于简化redux操作的react插件。主要对上一步进行改造。
安装插件
1
yarn add react-redux
修改入口文件
1
2
3
4
5import { Provider } from 'react-redux';
ReactDOM.render(
<Provider store={store}><App /></Provider>,
document.getElementById('root')
);在app组件中暴露的不是类,而是
connect
函数1
2
3
4
5
6
7import { connect } from 'react-redux'
import { increment, decrement } from '../redux/actions'
class App extends Component {}
export default connect((state) => ({ count: state }), {
increment,
decrement
})(App)
异步处理
redux默认不支持异步处理。因此如果在redux中使用异步操作应该使用插件redux-thunk
。
安装插件
1
yarn add redux-thunk
修改创建
srore
对象的结构1
2
3
4
5
6import { createStore, applyMiddleware } from 'redux'
import { counter } from './reducers'
import thunk from 'redux-thunk';
// 生成一个store对象
const store = createStore(counter, applyMiddleware(thunk)) // 内部第一次调用初始实例
export default store编写异步逻辑,编辑
action.js
文件1
2
3
4
5
6
7
8
9// 异步action
export const incrementAsync = (number) => {
return dispatch => {
setTimeout(() => {
// 1s之后才会去执行action
dispatch(increment(number))
}, 1000);
}
}
redux调试工具
谷歌浏览器安装插件
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd
项目安装插件
1
yarn add redux-devtools-extension
在项目中引用插件(store中)
1
2
3import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk';
const store = createStore(counter, composeWithDevTools(applyMiddleware(thunk)))
react-redux改造流程
创建好文件结构——创建
redux
文件,并创建如下文件actions.js
包含所有action creator(action的工厂函数)
actions-type.js
包含所有action的type常量
reducers.js
包含N个reducer函数。根据老的strate和action返回一个新的state
store.js
核心管理对象
入口文件引入
1
2
3
4
5
6
7
8
9import React from 'react';
import ReactDOM from 'react-dom';
// 引入Provider
import { Provider } from 'react-redux'
// 引入核心对象
import store from './redux/store'
import App from './components/app/app.jsx'
// 将根组件进行包裹
ReactDOM.render((<Provider store={store}><App /></Provider>), document.getElementById('root'));在根组件中引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14import { addComent, deleteComent } from '../../redux/actions'
class App extends Component {
static propTypes = {
comments: propTypes.array.isRequired,
addComent: propTypes.func.isRequired,
deleteComent: propTypes.func.isRequired
}
}
// 第一个参数取决于数据定义格式
export default connect((state) => ({ comments: state }), {
// 以下来源于action
addComent,
deleteComent
})(App)编辑
action-type.js
文件,定义type的常量即对数据操作的类型。
1
2
3
4// 添加评论
export const ADD_COMMENT = 'add_commont'
// 删除评论
export const DELETE_COMMENT = 'delete_comment'编辑
actions.js
文件。1
2
3
4
5
6// 包含所有action creator(action的工厂函数)
import { ADD_COMMENT, DELETE_COMMENT } from './action-type'
// 同步添加
export const addComent = (comment) => ({ type: ADD_COMMENT, data: comment })
// 同步删除
export const deleteComent = (index) => ({ type: DELETE_COMMENT, data: index })编辑
reducer.js
文件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 包含N个reducer函数
// 根据老的strate和action返回一个新的state
import { ADD_COMMENT, DELETE_COMMENT } from './action-type'
const initComments = [
{ username: 'Tom', content: 'react挺好的' },
{ username: 'Tom', content: 'react太难了' }
]
export function comments (state = initComments, action) {
switch (action.type) {
case ADD_COMMENT:
return [action.data, ...state]
case DELETE_COMMENT:
return state.filter((comment, index) => action.data !== index)
default:
return state
}
}编辑
store.js
文件1
2
3
4
5
6
7
8
9// 核心管理对象
import { createStore, applyMiddleware } from 'redux'
import { comments } from './reducers'
import thunk from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
export default createStore(comments,
composeWithDevTools(applyMiddleware(thunk))
)
添加异步操作
在
actions.js
文件中添加异步操作1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 包含所有action creator(action的工厂函数)
import { ADD_COMMENT, DELETE_COMMENT, RECEIVE_COMMENTS } from './action-type'
// 同步接收comments
const receiveComments = (comments) => ({ type: RECEIVE_COMMENTS, data: comments })
// 异步获取
export const getComment = () => {
return dispatch => {
// 模拟异步请求
setTimeout(() => {
const comments = [
{ username: 'Tom', content: 'react挺好的' },
{ username: 'Tom', content: 'react太难了' }
]
// 分发一个同步actions
dispatch(receiveComments(comments))
}, 1000);
}
}在
actions-type.js
中定义类型1
2// 异步获取
export const RECEIVE_COMMENTS = 'receive_comment'修改
reducers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 包含N个reducer函数
// 根据老的strate和action返回一个新的state
import { ADD_COMMENT, DELETE_COMMENT, RECEIVE_COMMENTS } from './action-type'
export function comments (state = initComments, action) {
switch (action.type) {
case ADD_COMMENT:
return [action.data, ...state]
case DELETE_COMMENT:
return state.filter((comment, index) => action.data !== index)
case RECEIVE_COMMENTS:
return action.data
default:
return state
}
}在根组件的生命周期中触发
1
2
3
4
5
6
7
8
9
10
11
12
13class App extends Component {
componentDidMount() {
// 异步获取评论数组
this.props.getComment()
}
}
// 第一个参数取决于数据定义格式
export default connect((state) => ({ comments: state }), {
// 以下来源于action
addComent,
deleteComent,
getComment
})(App)
reducers暴露多个
1 | import { combineReducers } from 'redux' |
在创建对象时管理的为reducers
1 | import reducers from './reducers' |
此时redux暴露的为对象结构,
{counter:xx,comments:xx}