redux是一个专门用于做状态管理的JS库(不是react插件库,不是官方的插件)。
它可以用在react, angular, vue等项目中, 但基本与react配合使用。
作用: 集中式管理react应用中多个组件共享的状态。
action : 动作的对象
有两个属性
举个例子:{type:'add',data:3}
用于初始化状态、加工状态。
加工时,根据旧的state和action, 产生新的state的纯函数。
// 完整的写法
1. npm install --save redux 安装redux
2. 在src下创建
-- redux
-- store.js
-- xxx_reducer.js
-- xxx_action.js
3. 在store.js
- 通过去引入redux中的createStore(),创建一个store
- createStore()在创建的时候需要传入一个指定服务的reducer
- 最后暴露store
示例:
// legacy_createStore是用于创建redux中最为核心的store
import {legacy_createStore as createStore} from "redux"
// 导入为xxx组件服务的reducer
import xxxReducer from "./xxx_reducer"
// 暴露store
export default createStore(xxxReducer)
4.在xxx_reducer.js
- reducer本质是一个函数,因为上述的操作导致它可以接收到两个参数previousState(之前的状态)和action(动作对象),在这里做一些操作然后返回加工后的状态
- reducer有两个作用:初始化状态和加工状态
- reducer第一次调用的时候,是store自动触发的,传入的previousState为undefined
示例:
let initState = 0
export default function countReducer(previousState = initState,action){
// 在action对象中可以获取两个参数,type和data
const {type,data} = action
switch (type) {
case 'plus':
return previousState + data*1
case 'subtract':
return previousState - data*1
default:
// 初始化
return previousState
}
}
5. 在xxx_action
这个文件是专门为xxx组件生成action对象
示例:
export const plusAction = data => ({type:'plus',data})
export const subtractAction = data => ({type:'subtract',data})
6. 创建一个文件constant.js,该文件是用来去定义action对象中type类型的常量,目的是为了避免程序员写错,便于管理
export const PLUS = 'plus'
export const SUBSCRIBE = 'subscribe'
// 上述工作完成后,redux文件就写好了
// 下面讲述在组件中怎么使用
7. 这里我创建一个count组件
下面示例中用到几个API,解释一下它们的作用
`store.getState()` 可以获取加工完后的状态
`store.dispatch(action)` 派发一个action给store,store在交给reducer加工
`store.subscribe(()=>{})` 可以监视redux状态的变化,如果发生变化就调用该函数
示例:
import React, { Component } from 'react'
// 引入store
import store from "../../redux/store"
// 引入action
import {plusAction,subtractAction} from "../../redux/count_action"
export default class Count extends Component {
render() {
return (
<div>
{/* 调用store上的getState()获取可以获取加工完后的状态 */}
<h1>当前的值为: {store.getState()}</h1>
<select ref={c=>this.selectVal = c}>
<option value="1"> 1 </option>
<option value="2"> 2 </option>
<option value="3"> 3 </option>
<option value="4"> 4 </option>
</select>
<button onClick={this.plus}> + </button>
<button onClick={this.subtract}> - </button>
<button onClick={this.oddPlus}> 奇数+ </button>
<button onClick={this.delayPlus}> 延迟+ </button>
</div>
)
}
componentDidMount(){
// subscribe去监视redux的状态是否发生变化,只要一发生变化就调用render()
store.subscribe(()=>{
// 可以利用setState,更新完状态后调用render()
this.setState({})
})
}
plus = () => {
// 去派发一个action
store.dispatch(plusAction(this.selectVal.value*1))
}
subtract = () => {
// 去派发一个action
store.dispatch(subtractAction(this.selectVal.value*1))
}
oddPlus = () => {
if(store.getState() % 2 !== 0){
// 去派发一个action
store.dispatch(plusAction(this.selectVal.value*1))
}
}
delayPlus = () => {
setTimeout(() => {
store.dispatch(plusAction(this.selectVal.value*1))
}, 500);
}
}
什么时候使用异步action呢?
当想要对状态进行修改的时候,但是具体的数据是靠异步任务返回的
同步action : action是一个对象
异步action : action是一个函数
import store from "./store"
// 返回的是一个对象,所以它是同步的action
export const subtractAction = data => ({type:SUBSCRIBE,data})
// 返回的是一个函数,并且用到了异步任务,所以它是异步的action
// 返回的函数由store帮忙调用
export const addAsyncAction = (data,time) =>{
return ()=>{
setTimeout(() => {
store.dispatch(plusAction(data))
}, time);
}
}
想要使用异步action,需要借助中间件
npm install redux-thunk
在store.js文件下
// legacy_createStore是用于创建redux中最为核心的store
// applyMiddleware用来支持使用中间件
import {legacy_createStore as createStore,applyMiddleware} from "redux"
// 导入为Count服务的reducer
import countReducer from "./count_reducer"
// 引入redux-thunk,用来支持使用异步action
import thunk from "redux-thunk"
// 暴露store
// 第一个参数用来接收reducer,第二个参数用来支持使用中间件
export default createStore(countReducer,applyMiddleware(thunk))
要和redux
区分开来, react-redux
一个react插件库
作用: 专门用来简化react应用中使用redux
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bMXyZjBA-1660203633424)(C:\Users\hp\Desktop\Note\图片\react-redux.png)]
这里需要明确三个点:
1. npm install react-redux 安装react-redux
2. 在src下创建一个containers文件,用于存放容器组件
3. 引入react-redux中connect这个方法,创建一个容器组件并且和UI组件建立联系
connect(mapStateToProps,mapDispatchToProps)(UI组件)
- mapStateToProps(state):映射状态,返回的是一个对象
- mapDispatchToProps(dispatch):映射的是操作对象的方法,返回的是一个对象
示例: 将UI组件和容器组件写一起,可以减少创建多个文件
import React, { Component } from 'react'
// 引入react-rudex中的connect
import {connect} from "react-redux"
// 引入action
import {plusAction} from "../../redux/count_action"
// 引入store
import store from "../../redux/store"
// UI组件
class Count extends Component {
render() {
return (
<div>
{/* 调用store上的getState()获取修改后的值 */}
<h1>当前的值为: {this.props.count}</h1>
<select ref={c=>this.selectVal = c}>
<option value="1"> 1 </option>
<option value="2"> 2 </option>
<option value="3"> 3 </option>
<option value="4"> 4 </option>
</select>
<button onClick={this.plus}> + </button>
</div>
)
}
plus = () => {
this.props.plus(this.selectVal.value)
}
}
const mapStateToProps = (state) =>{
/*
可以拿到总的state
mapStateToProps函数返回的是一个对象:
返回对象中key就作为传递UI组件props的key
返回对象中的value就作为传递UI组件props的value
作用:用于给UI组件传递状态
*/
return {count:state}
}
const mapDispatchToProps = (dispatch) =>{
/*
mapDispatchToProps函数返回的是一个对象
返回对象中key就作为传递UI组件props的key
返回对象中的value就作为传递UI组件props的value
作用:用于给UI组件传递操作状态的方法
*/
return {
plus:(data)=>{dispatch(plusAction(data))}
}
}
// 创建容器组件并且暴露
export default connect(mapStateToProps,mapDispatchToProps)(Count)
4.使用容器组件需要传入store,用于和redux建立联系
<容器组件 store={store}/>
当使用了connect方法后,它具备了监视redux的能力,所以不需要再写store.subscribe()
去监视redux状态的变化
下面代码就可以不用再写了
componentDidMount(){
// subscribe去监视redux的状态是否发生变化,只要一发生变化就调用render()
store.subscribe(()=>{
// 可以利用setState,更新完状态后调用render()
this.setState({})
})
}
// 创建容器组件并且暴露
export default connect(
state=>({count:state}),
/*
mapDispatchToProps也可以写成一个对象,
这个对象中的value只要传入对应的action,
当UI去调用时实际上是调用action的方法,返回一个{type:xx,data:xx}
那么react-redux就会自动帮我们去派发action
*/
{
plus:plusAction
}
)(Count)
<容器组件 store={store}/>
<容器组件 store={store}/>
<容器组件 store={store}/>
例如上述代码:如果容器组件很多那么需要传递很多store
provider组件的作用:减少容器组件中传递store
使用方法
在index.js中
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {Provider} from "react-redux"
import store from './redux/store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
{/* 在这里使用,表示App下的所有容器组件都有store,也就是和redux和容器组件建立联系 */}
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
只需要在store.js文件下再去引入combineReducers
// 引入legacy_createStore用来创建store
// 引入applyMiddleware用来支持使用中间件
// 引入combineReducers用来实现数据共享
import {legacy_createStore,applyMiddleware,combineReducers} from "redux"
// 引入支持异步action的中间件
import thunk from "redux-thunk"
// 引入reducer
import count_reducer from "./reducers/count_reducer"
import person_reducer from "./reducers/person_reducer"
// 切记:combineReducers传入的对象 === redux中保存的总状态对象
export default legacy_createStore(combineReducers({count_reducer,person_reducer}),applyMiddleware(thunk))
在读取状态的时候需要注意:
// 创建容器组件和UI组件建立联系,并且暴露
export default connect(
// 切记:combineReducers传入的对象 === redux中保存的总状态对象
// state.xxx
(state)=>({calculate:state.count_reducer,personNum:state.person_reducer}),
{
plus:plusAction
}
)(Count)
以上就是今天要讲的内容,希望对大家有所帮助!!!