文章目录
1. 理解redux
redux是一个独立专门用来做状态管理的js库(不是react插件库);
作用: 集中式管理react应用中多个组件共享的状态
2. 工作流程
3. 核心API
(1) createStore() : 创建包含指定reducer的store对象
(2) store对象: redux库最核心的管理对象; 将state,action与reducer联系在一起的对象
store.getState(): 得到state
store.dispatch(action): 分发action, 触发reducer调用, 产生新的state
store.subscribe(listener): 注册(订阅)监听, 一旦状态发生改变, 自动重新渲染
(3) action : 标识要执行行为的对象;获取异步数据
包含2个方面的属性:
type: 标识属性, 值为字符串, 唯一, 必要属性
xxx: 数据属性, 值类型任意, 可选属性
(4) reducer:根据老的state和action, 产生新的state的纯函数
a.返回一个新的状态
b.不要修改原来的状态
4. 安装
npm install --save redux
5. 案例
(1)创建store对象
// redux/store.js
import {createStore} from 'redux'
import {counter} from './reducer'
// 生成一个store对象 (接受reducer)
const store = createStore(counter)
export default store
(2)reducer
// redux/reducer.js
/*
根据老的state和指定action, 处理返回一个新的state
*/
// 导入常数
import {INCREMENT, DECREMENT} from './action_types'
export function counter(state = 0, action) {
// console.log('counter', state, action)
switch (action.type) {
case INCREMENT:
return state + action.number
case DECREMENT:
return state - action.number
default:
return state
}
}
(3) action
// redux/action.js
// action creator
import {INCREMENT, DECREMENT} from './action_types'
export const increment = number => ({type: INCREMENT, number})
export const decrement = number => ({type: DECREMENT, number})
(4) 常量
// redux/action_types.js
// action 常量的名称模块
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
(5)index.js 文件
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import store from './redux/store'
// 定义渲染根组件标签的函数
const render = () => {
ReactDOM.render(
<App store={store}/>,
document.getElementById('root')
)
}
// 初始化渲染
render()
// 注册(订阅)监听, 一旦状态发生改变, 自动重新渲染
store.subscribe(render)
(6)app.js
import React, { Component } from 'react';
import * as actions from './redux/action'
class App extends Component {
increment = ()=>{
// 分发action,触发reducer调用,产生新的state
this.props.store.dispatch(actions.increment(1))
}
decrement = ()=>{
this.props.store.dispatch(actions.decrement(1))
}
render() {
return (
<div>
<p> {this.props.store.getState()} </p>
<div>
<button onClick={this.increment}> + </button>
<button onClick={this.decrement}> - </button>
</div>
</div>
);
}
}
export default App;
问题:
- redux 与 react 组件的代码耦合度太高
- 编码不够简洁
6. react-redux
npm install --save react-redux
一个react插件库,专门用来简化react应用中使用redux
react-redux将所有组件分成两大类:UI组件 和 容器组件
- UI 组件 :只负责 UI 的呈现,不带有任何业务逻辑 ; 通过 props 接收数据(一般数据和函数) ; 不使用任何 Redux 的 API ; 一般保存在 components 文件夹下。
- 容器组件 : 负责管理数据和业务逻辑,不负责 UI 的呈现 ; 使用 Redux 的 API ; 一般保存在 containers 文件夹下
7. react-redux 相关API
- Provider
让所有组件都可以得到 state 数据
<Provider store={store}> <App /> </Provider>
- connect()
将UI组件包装成容器组件;链接react 与redux
state 返回一个对象
export default connect(
state => ({user: state.user}),
{updateUserInfo}
)(DashenInfo);
- mapStateToprops()
将 外部state(store仓库里的数据,也就是异步获取的数据) 转换为 UI 组件的标签属性;作为props绑定到组件上
export default connect(
state => ({user: state.user}),
{updateUserInfo}
)(DashenInfo);
- mapDispatchToProps()
将action作为props绑定到组件上 ,简洁语法可以直接指定为 actions 对象或包含多个 action 方法的对象
8. 案例改写
(1)components/counter.js
// UI 组件 不包含任何reduxAPI
import React, {Component} from 'react';
class Counter extends Component {
increment = ()=>{
this.props.increment(1)
};
decrement = ()=>{
this.props.decrement(1)
};
render() {
console.log(this);
return (
<div>
<p> {this.props.count} </p>
<div>
<button onClick={this.increment}> + </button>
<button onClick={this.decrement}> - </button>
</div>
</div>
);
}
}
export default Counter
(2)containers/App.js
// 包含counter组件的容器组件
import React from 'react';
// 链接react-redux redux
import {connect} from 'react-redux'
import {increment, decrement} from '../redux/action'
import Counter from "../components/Counter";
export default connect(
state =>(
{count:state}
),{increment, decrement}
)(Counter);
(3)redux 文件j夹 内容不变
(4)index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './containers/App';
import {Provider} from 'react-redux'
import store from './redux/store'
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
);
问题: redux 默认是不能进行异步处理
9. redux-thunk 异步编程(优先使用)
redux 异步中间件
npm install --save redux-thunk
10. 案例改写
(1)component/counter.js
// UI 组件 不包含任何reduxAPI
import React, {Component} from 'react';
class Counter extends Component {
increment = ()=>{
// 新增异步方法
this.props.incrementAsync(1)
};
decrement = ()=>{
this.props.decrement(1)
};
render() {
console.log(this);
return (
<div>
<p> {this.props.count} </p>
<div>
<button onClick={this.increment}> + </button>
<button onClick={this.decrement}> - </button>
</div>
</div>
);
}
}
export default Counter
(2)app.js
// 包含counter组件的容器组件
import React from 'react';
// 链接react-redux redux
import {connect} from 'react-redux'
import {increment, decrement, incrementAsync} from '../redux/action'
import Counter from "../components/Counter";
export default connect(
state =>(
{count:state}
),{increment, decrement, incrementAsync}
)(Counter);
(3) store.js
import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import {counter} from './reducer'
export default createStore(counter, applyMiddleware(thunk))
(4) action.js
export const increment = number => ({type: 'increment', number});
export const decrement = number => ({type: 'decrement', number});
export const incrementAsync = number =>{
return dispatch =>{
setTimeout(()=>{
dispatch(increment(number))
}, 1000)
}
};
11. 使用总结
(1)模块安装
npm i --save redux react-redux redux-thunk
(2)创建文件夹
reducer.js
/*
包含多个用于生成新的state的reducer函数的模块
*/
import {combineReducers} from 'redux'
function xxx(state=0, action) {
return state
}
function yyy(state=0, action) {
return state
}
export default combineReducers({
xxx,yyy
})
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app'
import {BrowserRouter} from 'react-router-dom'
import 'antd/dist/antd.css';
import {Provider} from 'react-redux'
import store from './redux/store'
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App></App>
</BrowserRouter>
</Provider>
,
document.getElementById('root')
);
store.js
/*
redux最核心的store对象模块
*/
import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import reducers from './reducer'
export default createStore(reducers, applyMiddleware(thunk))
ui 组件封装成容器组件
import {connect} from 'react-redux'
export default connect(
state=>({state: state}),
{}
)(Right);