redux是什么
- redux是一个专门用于做状态管理的JS库(不是react插件库)。
- 它可以用在react, angular, vue等项目中, 但基本与react配合使用。
- 作用: 集中式管理react应用中多个组件共享的状态。
redux的三个核心概念
action作为store.dispatch()的参数,通知reducer如何修改
reducer修改数据
action
- 动作的对象
- 包含2个属性
- type:标识属性, 值为字符串, 唯一, 必要属性
- data:数据属性, 值类型任意, 可选属性
- 例子:{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} }
reducer
- 用于初始化状态、加工状态。
- 加工时,根据旧的state和action, 产生新的state的纯函数。
store
- 将state、action、reducer联系在一起的对象
- 如何得到此对象?
- import {createStore} from 'redux'
- const store = createStore(reducer)
- import reducer from './reducers'
- import {createStore} from 'redux'
- 此对象的功能?
- getState(): 得到state
- subscribe(listener): 注册监听, 当产生了新的state时, 自动调用
- dispatch(action): 分发action, 触发reducer调用, 产生新的state
- getState(): 得到state
redux的核心API
createstore()
作用:创建包含指定reducer的store对象
store对象
- 作用: redux库最核心的管理对象
- 它内部维护着:
- state
- reducer
- state
- 核心方法:
- getState()
- dispatch(action)
- subscribe(listener)
- getState()
- 具体编码:
- store.getState()
- store.dispatch({type:'INCREMENT', number})
- store.subscribe(render)
- store.getState()
applyMiddleware()
作用:应用上基于redux的中间件(插件库)
combineReducers()
作用:合并多个reducer函数
import React, { Component } from 'react'
import store from '../../redux/store'
export default class index extends Component {
componentDidMount(){
//监测redux中状态的变化,只要变化,就调用render
store.subscribe(()=>{
this.setState({})
})
}
//加法
increment = ()=>{
//通知redux + value
const {value} = this.selectNumber
store.dispatch({type:'increment',data:value*1})
}
//减法
decrement = ()=>{
const {value} = this.selectNumber
store.dispatch({type:'decrement',data:value*1})
}
//奇数再加
incrementOdd = ()=>{
const {value} = this.selectNumber
const sum = this.getState()
if(sum % 2 !==0){
store.dispatch({type:'increment',data:value*1})
}
}
//异步加
incrementAsync = ()=>{
const {value} = this.selectNumber
setTimeout(() => {
store.dispatch({type:'increment',data:value*1})
}, 500);
}
render() {
return (
<div>
<h1>当前和为:{store.getState()}</h1>
<select name="" id="" ref={c=>this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
)
}
}
异步actions
redux异步编程
理解:
- redux默认是不能进行异步处理的,
- 某些时候应用中需要在redux中执行异步任务(ajax, 定时器)
使用异步中间件
npm install --save redux-thunk
react-redux
理解
- 一个react插件库
- 专门用来简化react应用中使用redux
react-Redux将所有组件分成两大类
- UI组件
-
- 只负责 UI 的呈现,不带有任何业务逻辑
- 通过props接收数据(一般数据和函数)
- 不使用任何 Redux 的 API
- 一般保存在components文件夹下
-
- 容器组件
-
- 负责管理数据和业务逻辑,不负责UI的呈现
- 使用 Redux 的 API
- 一般保存在containers文件夹下
-
相关API
1.Provider:让所有组件都可以得到state数据
2.connect:用于包装 UI 组件生成容器组件
3.mapStateToprops:将外部的数据(即state对象)转换为UI组件的标签属性
4.mapDispatchToProps:将分发action的函数转换为UI组件的标签属性
容器组件
//引入UI组件
import CountUI from '../../components/Count'
//引入用于连接UI组件与redux
import {connect} from 'react-redux'
import {incrementAction,decrementAction,incrementAsyncAction} from '../../redux/count_action'
//函数的返回对象中的key作为传递给UI组件props的key,value就作为作为传递给UI组件props的value----状态
function mapStateToProps(state){
return{count:state}
}
//函数返回的对象中的key作为传递给UI组件props的key,value就作为作为传递给UI组件props的value----操作状态的方法
function mapDispatchToProps(dispatch){
return{
plus:(value)=>{dispatch(incrementAction(value*1))},
reduce:(value)=>{dispatch(decrementAction(value*1))},
asyncPlus:(value,time)=>{dispatch(incrementAsyncAction(value*1,time))},
}
}
//使用connect()()创建并暴露一个容器组件
const CountContainer = connect(mapStateToProps,mapDispatchToProps)(CountUI)
export default CountContainer
action作为store.dispatch()的参数,通知reducer如何修改
reducer修改数据
优化一: 简写mapDispatch
//引入UI组件
import CountUI from '../../components/Count'
//引入用于连接UI组件与redux
import { connect } from 'react-redux'
import { incrementAction, decrementAction, incrementAsyncAction } from '../../redux/count_action'
//函数的返回对象中的key作为传递给UI组件props的key,value就作为作为传递给UI组件props的value----状态
// function mapStateToProps(state){
// return{count:state}
// }
// const mapStateToProps = state => ({ count: state })
//函数返回的对象中的key作为传递给UI组件props的key,value就作为作为传递给UI组件props的value----操作状态的方法
// function mapDispatchToProps(dispatch) {
// return {
// plus: (value) => { dispatch(incrementAction(value * 1)) },
// reduce: (value) => { dispatch(decrementAction(value * 1)) },
// asyncPlus: (value, time) => { dispatch(incrementAsyncAction(value * 1, time)) },
// }
// }
// const mapDispatchToProps = dispatch => ({
// plus: (value) => { dispatch(incrementAction(value * 1)) },
// reduce: (value) => { dispatch(decrementAction(value * 1)) },
// asyncPlus: (value, time) => { dispatch(incrementAsyncAction(value * 1, time)) },
// })
//使用connect()()创建并暴露一个容器组件
const CountContainer = connect(
state => ({ count: state }),
// dispatch => ({
// plus: (value) => { dispatch(incrementAction(value * 1)) },
// reduce: (value) => { dispatch(decrementAction(value * 1)) },
// asyncPlus: (value, time) => { dispatch(incrementAsyncAction(value * 1, time)) },
// })
{
plus:incrementAction,
reduce:decrementAction,
asyncPlus:incrementAsyncAction,
}
)(CountUI)
export default CountContainer
优化二: Provider组件的使用
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom'
import store from './redux/store'
import {Provider} from 'react-redux'
const root = ReactDOM.createRoot(document.getElementById('root'));
// store.subscribe(()=>{
// root.render(
// <React.StrictMode>
// <BrowserRouter>
// <App />
// </BrowserRouter>
// </React.StrictMode>
// );
// })
//React.StrictMode 监测代码是否合理
//渲染app到页面
root.render(
<React.StrictMode>
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>
</React.StrictMode>
);
reportWebVitals();
优化三: 整合UI组件和容器组件
import React, { Component } from 'react'
//引入用于连接UI组件与redux
import { connect } from 'react-redux'
import { incrementAction, decrementAction, incrementAsyncAction } from '../../redux/count_action'
class Count extends Component {
// componentDidMount(){
// //监测redux中状态的变化,只要变化,就调用render
// store.subscribe(()=>{
// this.setState({})
// })
// }
componentDidMount(){
console.log('???',this.props)
}
//加法
increment = ()=>{
//通知redux + value
const {value} = this.selectNumber
this.props.plus(value*1)
}
//减法
decrement = ()=>{
const {value} = this.selectNumber
this.props.reduce(value*1)
}
//奇数再加
incrementOdd = ()=>{
const {value} = this.selectNumber
const sum = this.props.count
if(sum % 2 !== 0){
this.props.plus(value*1)
}
}
//异步加
incrementAsync = ()=>{
const {value} = this.selectNumber
//store.dispatch(incrementAsyncAction(value*1,500))
this.props.asyncPlus(value*1,500)
}
render() {
return (
<div>
<h1>当前和为:{this.props.count}</h1>
<select name="" id="" ref={c=>this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
)
}
}
//使用connect()()创建并暴露一个容器组件
export default connect(
state => ({ count: state }),
{
plus:incrementAction,
reduce:decrementAction,
asyncPlus:incrementAsyncAction,
}
)(Count)
import { applyMiddleware, legacy_createStore as createStore, combineReducers} from 'redux'
import countReducer from './reducers/count_reducer'
import personReducer from './reducers/person'
import thunk from 'redux-thunk'
import {composeWithDevTools} from 'redux-devtools-extension'
//传入的参数就是redux所维护的状态对象
const allReducer = combineReducers({
persons:personReducer,
sum:countReducer,
})
export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))
import { applyMiddleware, legacy_createStore as createStore, combineReducers} from 'redux'
import countReducer from './reducers/count_reducer'
import personReducer from './reducers/person'
import thunk from 'redux-thunk'
import {composeWithDevTools} from 'redux-devtools-extension'
//传入的参数就是redux所维护的状态对象
const allReducer = combineReducers({
persons:personReducer,
sum:countReducer,
})
export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))
多个reducer会逐个匹配,default 的 返回值 要返回当前值。