Redux
Redux是JavaScript应用的状态容器,提供可预测的状态管理,功能与vueX一样;上述脚手架并未自动安装上redux,需自行安装~
npm install redux
注意:Redux并不是只为react框架提供状态管理功能,它也支持其它前端框架,并不是由Facebook打造的产品~
通过使用Redux,可以集中式存储和管理应用的状态;在处理组件通信问题时,可以无视组件之间的层级关系;
它有三个核心概念:action、store以及reducer;
action、store与reducer
- action
见名之意,action用于定义动作,它其实
就是一个包含type以及data属性的js对象,
其中type属性属于标识属性,用于区分动作的类型,而data属性为可选属性,表示本次动作携带的数据;action只用于描述要做什么,并不真正执行动作(完成响应功能);
{ type: 'increment' }
{ type: 'decrement', data: 2 }
{ type: 'addTodo', data: '吃饭' }
{ type: 'removeTodo', data: {name: '睡觉', done: false} }
- store
见名之意,store表示仓库,它是Redux的核心功能,用于整合action以及reducer;
注意,一个应用(项目)中只有一个store!
store由于地位特殊,身上封装了很多操作功能的API:
store.getStore() // 获取维护的状态
const store = createStore(xxxreducer) // 创建store 要接收对应的reducer作为参数
store.dispatch(xxxaction) // 分发动作,进行状态更新 要接收指定action作为参数
store.subscribe(() => {}) // 订阅状态变化(监听状态变化)
- reducer
reducer是真正执行action动作的地方,
它其实就是一个函数,用于初始化状态以及修改状态;
该函数接收两个参数(previousState, action),分别是旧状态和要执行的action,根据传入的不同action分别进行不同的处理,
返回不同的新状态值
。通常与switch case语句结合~
const initState = 10 // 初始化状态
const reducer = (preState = initState, action) => {
const {type, data} = action
switch (type) {
case 'jia':
// 返回新的state
return preState + data
case 'jian':
// 返回新的state
return preState - data
default:
return preState // 若不匹配任何动作,则为初始化状态
}
}
可指定action动作的初始值,若不匹配任何action,则会执行初始化动作,可在reducer中进行定义~
Redux代码执行过程
①创建store
只要创建store,那么,Redux就会调用一次reducer(此时的type是一个随机值,类似于
@@redux/INIT5.s.d.l.5
的样式),此次调用reducer是为了给状态初始化(获取状态的默认值)
注意:若有多个状态管理,则要创建多个reducer,并利用
combineReducers
方法将多个reducer汇总传给store;
②更新状态
当需要更新状态时,首先要分发动作store.dispatch(action),随后调用euducer,计算出新的状态并返回;
③获取最新状态
React-Redux
React-Redux是redux官方react绑定库,专门用来简化react使用redux,安装脚手架时并未主动安装上react-redux,需单独安装,
一般与原生redux结合使用;
npm install react-redux
React-Redux将所有组件分为两大类:
UI组件和容器组件;
其中UI组件只负责页面的呈现、交互,不能使用redux中的任何API;
容器组件负责和redux通信,将数据传给UI组件;
容器组件包裹UI组件,组成父子组件;
容器组件会传给UI组件:①redux中所保存的状态 ②用来操作状态的方法;这两个都要通过props传递;
容器组件与UI组件形成父子关系的方法不是通过标签包裹实现的,而是通过react-redux中的connect函数实现的;
import { connect } from 'react-redux'
connect(mapStateToProps, mapDispatchToProps)(UI组件)
// mapStateToProps: 映射状态,返回值是一个对象
// mapDispatchToProps: 映射操作状态的方法,返回值是一个对象;
connet方法接收两个
函数
参数,第一个表示要传入子组件的state,第二个参数表示要传入子组件的操作状态的方法,返回值均为一个对象;
示例
下面通过四种方式将两兄弟组件(Count与Person组件)的通信方式进行比较:
通过prop传递事件进行通信
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// App.js组件
import { Component } from 'react';
import Count from './components/Count'
import Person from './components/Person'
import { nanoid } from 'nanoid';
import './App.css';
export default class App extends Component {
state = {
count: 0,
person: []
}
addPerson = (name, age) => {
const obj = {
name: name,
age: age,
id: nanoid()
}
if (!name || !age) return
this.setState({person: [...this.state.person, obj]})
}
increment = (val) => {
this.setState({count: this.state.count + val * 1})
}
decrement = (val) => {
this.setState({count: this.state.count - val * 1})
}
render() {
return (
<div className="App">
<Count {...this.state} addPerson={this.addPerson} increment={this.increment} decrement={this.decrement}/>
<hr/>
<Person {...this.state} addPerson={this.addPerson} increment={this.increment} decrement={this.decrement}/>
</div>
)
}
}
// Count.jsx组件
import React, { Component } from 'react'
export default class Count extends Component {
render() {
const {count, person} = this.props
return (
<div>
<h1>这是Count组件</h1>
<h2>Person组件的人数是:{person.length}</h2>
<h2>求和值是{count}</h2>
<select ref = {(ele) => {this.selectValue = ele}}>
<option value="1">1</option>
<option value="2">2</option>
</select>
<button onClick = {()=>{this.props.increment(this.selectValue.value)}}>加</button>
<button onClick = {()=>{this.props.decrement(this.selectValue.value)}}>减</button>
</div>
)
}
}
// Person.jsx组件
import React, { Component } from 'react'
export default class Person extends Component {
render() {
return (
<div>
<h1>这是Person组件</h1>
<h2>Count组件的数字是:{this.props.count}</h2>
<ul>
{this.props.person.map((p) => {
return <li key={p.id}>{p.name} --- {p.age}</li>
})}
</ul>
<input ref={(ele) => {this.name = ele}} type="text" placeholder='请输入名称'/>
<input ref={(ele) => {this.age = ele}} type="text" placeholder='请输入年龄'/>
<button onClick={() => {this.props.addPerson(this.name.value,this.age.value)}}>添加</button>
</div>
)
}
}
使用prop进行父子间通信较为方便,若是兄弟组件进行通信,则不仅要将状态通过prop传递,也要将事件通过prop进行传递(通过子组件调用父组件的方法),较为麻烦~
通过消息订阅方式
该方法通过安装PubSubJs库使用,首先在项目中进行安装:
npm install pubsub-js
并在项目中进行引入
import PubSub from 'pubsub-js'
该库主要通过
subscribe(订阅消息)和publish(发布消息)
方法进行使用;
const xxxPid = PubSub.subscribe('xxx消息', (msg, data) => {}) // 订阅消息,msg就是xxx消息,data是接收到的数据
PubSub.publish('xxx消息', data) // 发布xxx消息,data就是要进行发布的数据
PubSub.unsubscribe(xxxPid) // 取消订阅某消息
// index.js与上一方法相同
// App.js组件
import { Component } from 'react';
import Count from './components/Count'
import Person from './components/Person'
import './App.css';
export default class App extends Component {
render() {
return (
<div className="App">
<Count/>
<hr/>
<Person/>
</div>
)
}
}
// Count.jsx组件
import React, { Component } from 'react'
import PubSub from 'pubsub-js'
export default class Count extends Component {
state = {
count: 0,
length: 0
}
increment = (val) => {
this.setState({count: this.state.count + val * 1})
PubSub.publish('increment', this.state.count + val * 1) // 发布increment,并将数据传过去
}
decrement = (val) => {
this.setState({count: this.state.count - val * 1})
PubSub.publish('decrement', this.state.count - val * 1) // 发布decrement,并将数据传过去
}
componentDidMount() {
// 订阅addPerson, 利用回调函数接收数据并进行处理
this.add = PubSub.subscribe('addPerson', (msg, data) => {
this.setState({length: data.length})
})
}
componentWillUnmount() {
PubSub.unsubscribe(this.token) // 取消订阅token
}
render() {
return (
<div>
<h1>这是Count组件</h1>
<h2>Person组件的人数是:{this.state.length}</h2>
<h2>求和值是{this.state.count}</h2>
<select ref = {(ele) => {this.selectValue = ele}}>
<option value="1">1</option>
<option value="2">2</option>
</select>
<button onClick = {()=>{this.increment(this.selectValue.value)}}>加</button>
<button onClick = {()=>{this.decrement(this.selectValue.value)}}>减</button>
</div>
)
}
}
// Person.jsx组件
import React, { Component } from 'react'
import { nanoid } from 'nanoid';
import PubSub from 'pubsub-js'
export default class Person extends Component {
state = {
count: 0,
person: []
}
addPerson = (name, age) => {
console.log(PubSub);
const obj = {
name: name,
age: age,
id: nanoid()
}
if (!name || !age) return
this.setState({person: [...this.state.person, obj]})
PubSub.publish('addPerson', [...this.state.person, obj])
}
componentDidMount() {
this.jia = PubSub.subscribe('increment', (msg, data) => {
// 这里用了箭头函数才能取到setState
this.setState({count: data})
})
this.jian = PubSub.subscribe('decrement', (msg, data) => {
// 这里用了箭头函数才能取到setState
this.setState({count: data})
})
}
componentWillUnmount() {
PubSub.unsubscribe(this.jia) // 取消订阅jia
PubSub.unsubscribe(this.jian) // 取消订阅jian
}
render() {
return (
<div>
<h1>这是Person组件</h1>
<h2>Count组件的数字是:{this.state.count}</h2>
<ul>
{this.state.person.map((p) => {
return <li key={p.id}>{p.name} --- {p.age}</li>
})}
</ul>
<input ref={(ele) => {this.name = ele}} type="text" placeholder='请输入名称'/>
<input ref={(ele) => {this.age = ele}} type="text" placeholder='请输入年龄'/>
<button onClick={() => {this.addPerson(this.name.value,this.age.value)}}>添加</button>
</div>
)
}
}
补充:安装库的时候要注意是pubsub-js,而不是pubsub.js,虽都是消息订阅与发布库,但是传的参数是不一样的!
该方法为非官网出品,大型项目还是尽量少用~
状态管理之原生redux
// app.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals'; // 页面性能分析文件(需要web-vitals库的支持)
import store from './store/store'
const root = ReactDOM.createRoot(document.getElementById('root'));
// react.strictMode用于开启对app及其子组件的语法检查,不加也没啥
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
store.subscribe(() => {
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
})
// redux仅是进行状态管理,但是并不会对页面上的状态并不会主动更新,需要订阅store.subscribe
// 监视状态变化,若变化了则重新渲染页面
状态管理文件夹:
// store/store.js
// 该文件用于创建store,整个应用只有一个store对象
import { createStore } from 'redux'
import combineReducers from './reducer'
export default createStore(combineReducers) // 创建store
// store/reducer/count.js
// 该文件是为创建一个为count组件服务的reducer,reducer的本质是一个函数
// 它会接收到两个参数,第一个是previousState,另一个参数是action动作对象
const initState = 0 // 定义初始值
export default function countReducer(previousState = initState, action) {
const {type, data} = action
switch (type) {
case 'increment':
return previousState + data// 返回新数据
case 'decrement':
return previousState - data// 返回新数据
default:
return previousState // 若不匹配任何动作,则为初始化,返回初始值
}
}
// store/reducer/person.js
const initState = []
export default (previousState = initState, action) => {
const {type, data} = action
switch (type) {
case 'addPerson':
return [...previousState, data]
default:
return previousState;
}
}
// store/reducer/index.js
import { combineReducers } from 'redux'
import count from './count'
import person from './person'
export default combineReducers({count, person})
// store/action/count.js
export const incrementAction = (data) => ({type: 'increment', data}) // 返回一个对象
export const decrementAction = (data) => ({type: 'decrement', data}) // 返回一个对象
// store/actions/person.js
export const addPerson = (data) => ({type: 'addPerson', data}) // 返回一个对象
组件代码如下:
// components/Count.jsx
import React, { Component } from 'react'
import store from '../store/store'
import {incrementAction, decrementAction} from '../store/action/count'
export default class Count extends Component {
increment = (val) => {
store.dispatch(incrementAction(val * 1)) // 分发动作
}
decrement = (val) => {
store.dispatch(decrementAction(val * 1)) // 分发动作
}
render() {
return (
<div>
<h1>这是Count组件</h1>
<h2>Person组件的人数是:{store.getState().person.length}</h2>
<h2>求和值是{store.getState().count}</h2>
<select ref = {(ele) => {this.selectValue = ele}}>
<option value="1">1</option>
<option value="2">2</option>
</select>
<button onClick = {()=>{this.increment(this.selectValue.value)}}>加</button>
<button onClick = {()=>{this.decrement(this.selectValue.value)}}>减</button>
</div>
)
}
}
// components/Person.jsx
import React, { Component } from 'react'
import { nanoid } from 'nanoid';
import store from '../store/store'
import { addPerson } from "../store/action/person";
export default class Person extends Component {
addPerson = (name, age) => {
const obj = {
name: name,
age: age,
id: nanoid()
}
if (!name || !age) return
store.dispatch(addPerson(obj))
}
render() {
return (
<div>
<h1>这是Person组件</h1>
<h2>Count组件的数字是:{store.getState().count}</h2>
<ul>
{store.getState().person.map((p) => {
return <li key={p.id}>p.name---p.age</li>
})}
</ul>
<input ref={(ele) => {this.name = ele}} type="text" placeholder='请输入名称'/>
<input ref={(ele) => {this.age = ele}} type="text" placeholder='请输入年龄'/>
<button onClick={() => {this.addPerson(this.name.value,this.age.value)}}>添加</button>
</div>
)
}
}
使用原生redux方法需注意两点:
① redux并
不会主动监测
状态更新,所以状态更新后不会主动渲染页面,需要我们编写代码进行监测:一般在入口文件index.js文件中利用
store.subscribe
方法进行监测(发现改变立即重新渲染页面);
store.subscribe(() => {
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
})
②通过combineReducers将所有的reducer整合到一起,利用store进行管理,从而实现状态共享;
③在使用状态中数据时使用store.getState()方法拿到所有状态对象,根据情况取到正确的数据~
状态管理之react-redux
// App.jsx
import { Component } from 'react';
import Count from './components/Count'
import Person from './components/Person'
import './App.css';
import store from './store/store';
export default class App extends Component {
render() {
return (
<div className="App">
<Count store={store}/>
<hr/>
<Person store={store}/>
</div>
)
}
}
// components/Count/index.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux' // 引用connect
import {incrementAction, decrementAction} from '../../store/action/count'
class Count extends Component {
increment = (val) => {
this.props.sum(val * 1)
}
decrement = (val) => {
this.props.sub(val * 1)
}
render() {
return (
<div>
<h1>这是Count组件</h1>
<h2>Person组件的人数是:{this.props.person.length}</h2>
<h2>求和值是{this.props.count}</h2>
<select ref = {(ele) => {this.selectValue = ele}}>
<option value="1">1</option>
<option value="2">2</option>
</select>
<button onClick = {()=>{this.increment(this.selectValue.value)}}>加</button>
<button onClick = {()=>{this.decrement(this.selectValue.value)}}>减</button>
</div>
)
}
}
function mapStateToProps(state) {
return {
count: state.count,
person: state.person
}
}
function mapDispatchToProps(dispatch) {
return {
sum: number => dispatch(incrementAction(number)), // 映射加的动作到props
sub: number => dispatch(decrementAction(number)) // 映射减的动作到props
}
}
// 利用connect将生成Count组件对应的容器组件,并暴露出去
export default connect(mapStateToProps,mapDispatchToProps)(Count)
// components/Person/index.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux'
import { nanoid } from 'nanoid';
import { addPerson } from '../../store/action/person';
class Person extends Component {
addPerson = (name, age) => {
const obj = {
name: name,
age: age,
id: nanoid()
}
if (!name || !age) return
this.props.addPerson(obj)
}
render() {
return (
<div>
<h1>这是Person组件</h1>
<h2>Count组件的数字是:{this.props.count}</h2>
<ul>
{this.props.person.map((p) => {
return <li key={p.id}>{p.name}---{p.age}</li>
})}
</ul>
<input ref={(ele) => {this.name = ele}} type="text" placeholder='请输入名称'/>
<input ref={(ele) => {this.age = ele}} type="text" placeholder='请输入年龄'/>
<button onClick={() => {this.addPerson(this.name.value,this.age.value)}}>添加</button>
</div>
)
}
}
function mapStateToProps(state) {
return {
count: state.count,
person: state.person
}
}
function mapDispatchToProps(dispatch) {
return {
addPerson: data => dispatch(addPerson(data))
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Person)
// store/store.js
// 该文件用于创建store,整个应用只有一个store对象
import { createStore } from 'redux'
import combineReducers from './reducer'
export default createStore(combineReducers) // 创建store
// store/reducer/count.js
// 该文件是为创建一个为count组件服务的reducer,reducer的本质是一个函数
// 它会接收到两个参数,第一个是previousState,另一个参数是action动作对象
const initState = 0 // 定义初始值
export default function countReducer(previousState = initState, action) {
const {type, data} = action
switch (type) {
case 'increment':
return previousState + data// 返回新数据
case 'decrement':
return previousState - data// 返回新数据
default:
return previousState // 若不匹配任何动作,则为初始化,返回初始值
}
}
// store/reducer/person.js
const initState = []
export default function personReducer(previousState = initState, action) {
const {type, data} = action
switch (type) {
case 'addPerson':
return [...previousState, data];
default:
return previousState;
}
}
// store/reducer/index.js
// 该文件用于将所有的reducer进行汇总
import { combineReducers } from 'redux'
import person from './person'
import count from './count'
export default combineReducers({
person,
count
})
// store/action/count.js
export const incrementAction = (data) => ({type: 'increment', data}) // 返回一个对象
export const decrementAction = (data) => ({type: 'decrement', data}) // 返回一个对象
// store/action/person.js
export const addPerson = (data) => ({type: 'addPerson', data})
代码文件目录如下:
上述几个文件已可以实现所要功能,但有几个地方要进行详细探讨:
- createStore
该函数接收reducer作为参数,用于为本次项目创建一个store,基于后续redux的操作皆是源于该store;
还要注意的一点是组件中的store对象并不是通过引用store文件拿到的,而是通过其父组件传过来的(本次示例是通过在App.js引入store文件,然后利用父子间同信传过去的)
- 容器组件与UI组件
一般将容器组件与UI组件写到一个文件中,
暴露容器组件
;
- 自动监视state的变化
原生redux只是对状态进行了处理,但是不负责检测状态改变,要自己通过渲染组件的方式重新获取当前状态,react-redux对这点进行了改进,使得用到状态的容器组件自动检测状态改变,从而渲染页面,使页面始终保持最新数据;
与原生redux不一样,react-redux可自动检测
- 使用Provider
由于每个使用react-redux中的组件都要通过父组件拿到store,因此采用Provider组件将子组件包裹,并在Provider组件中传入store的方式较为方便些~(使用之前要先引入),一般采用在入口文件index.js中直接将App.js组件包裹的方式,是App.js的所有后代组件都能接收到store;
import { Provider } from 'react-redux';
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals'; // 页面性能分析文件(需要web-vitals库的支持)
import { Provider } from 'react-redux';
import store from './store/store'
import './index.css';
const root = ReactDOM.createRoot(document.getElementById('root'));
// react.strictMode用于开启对app及其子组件的语法检查,不加也没啥
root.render(
<React.StrictMode>
<Provider store = {store}>
<App />
</Provider>
</React.StrictMode>
- connect(mapStateToProps, mapDispatchToProps)(UI组件)函数
connect函数中的两个
函数
参数分别映射redux中的状态和动作,
其实第二个参数也可以传入一个对象,
将对应的action动作指明即可,不需要传递参数,因为action中已经定义了参数,react-redux会自动识别对应哪个动作和传入的参数;
// components/Person/index.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux'
import { nanoid } from 'nanoid';
import { addPerson } from '../../store/action/person'
class Person extends Component {
addPerson = (name, age) => {
const obj = {
name: name,
age: age,
id: nanoid()
}
if (!name || !age) return
this.props.addPerson(obj)
}
render() {
return (
<div>
<h1>这是Person组件</h1>
<h2>Count组件的数字是:{this.props.count}</h2>
<ul>
{this.props.person.map((p) => {
return <li key={p.id}>{p.name}---{p.age}</li>
})}
</ul>
<input ref={(ele) => {this.name = ele}} type="text" placeholder='请输入名称'/>
<input ref={(ele) => {this.age = ele}} type="text" placeholder='请输入年龄'/>
<button onClick={() => {this.addPerson(this.name.value,this.age.value)}}>添加</button>
</div>
)
}
}
export default connect(
(state) => ({count: state.count, person: state.person}),
{addPerson: addPerson}, // 动作映射可以写成一个对象
)(Person)
// components/Count/index.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux' // 引用connect
import {incrementAction, decrementAction} from '../../store/action/count'
class Count extends Component {
increment = (val) => {
this.props.sum(val * 1)
}
decrement = (val) => {
this.props.sub(val * 1)
}
incrementAsync = (val) => {
setTimeout(() => {
this.props.sum(val * 1)
}, 1000)
}
render() {
return (
<div>
<h1>这是Count组件</h1>
<h2>Person组件的人数是:{this.props.person.length}</h2>
<h2>求和值是{this.props.count}</h2>
<select ref = {(ele) => {this.selectValue = ele}}>
<option value="1">1</option>
<option value="2">2</option>
</select>
<button onClick = {()=>{this.increment(this.selectValue.value)}}>加</button>
<button onClick = {()=>{this.decrement(this.selectValue.value)}}>减</button>
<button onClick = {()=>{this.incrementAsync(this.selectValue.value)}}>异步加</button>
</div>
)
}
}
// 利用connect将生成Count组件对应的容器组件,并暴露出去
export default connect(
(state) => ({
count: state.count,
person: state.person
}),
{
sum: incrementAction,
sub: decrementAction
}, // 传入要映射到props中的动作
)(Count)
扩展:箭头函数若只返回一个对象,则可以在外侧包一个括号,则返回为一个函数,如本例中:
(state) => ({
count: state.count,
person: state.person
})
- combineReducers({})函数
该函数用于整合所有的reducer,将整合后的reducer传给createStore方法,合并后的总状态变成了一个对象,则状态管理store中就会包含多个状态,从而实现数据共享;
如本例中store状态中包含count和person两个数据,使用时要取对值~
纯函数
纯函数是一类特殊的函数,最大的特点是:
对于同样的输入,必定得到同样的输出
!
它遵守一些约定:
① 不得改写参数数据
② 不会产生任何副作用,如网络请求,输入和输出设备
③ 不能调用Date.now()或者Math.random()等方法
必须保证redux的reducer函数必须是一个纯函数!
基于此,所以本例中对于person的reducer并没有采用数组的push或unshift方法,因为它改变了参数数据(数组的push、unshift方法会改变原数组,即改变参数previousState):
const initState = []
export default function personReducer(previousState = initState, action) {
const {type, data} = action
switch (type) {
case 'addPerson':
return [...previousState, data]; // 此处并没有使用数据的方法
default:
return previousState;
}
}
异步action的处理
一般对于异步action的处理,可以通过在组件中定义好逻辑,然后调用同步action,如:
// components/Count/index.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux' // 引用connect
import {incrementAction} from '../../store/action/count'
class Count extends Component {
incrementAsync = (val) => {
setTimeout(() => { // 写异步逻辑
this.props.sum(val * 1) // 调用同步action
}, 1000)
}
render() {
return (
<div>
<h1>这是Count组件</h1>
<h2>Person组件的人数是:{this.props.person.length}</h2>
<h2>求和值是{this.props.count}</h2>
<select ref = {(ele) => {this.selectValue = ele}}>
<option value="1">1</option>
<option value="2">2</option>
</select>
<button onClick = {()=>{this.incrementAsync(this.selectValue.value)}}>异步加</button>
</div>
)
}
}
// 利用connect将生成Count组件对应的容器组件,并暴露出去
export default connect(
(state) => ({
count: state.count,
}),
{
sum: incrementAction,
}, // 传入要映射到props中的动作
)(Count)
当然,也可以通过直接在action中定义异步方法实现,此时的
action返回的是一个函数,该函数自带有dispatch这个参数~
需要安装redux-thunk库配合实现;
npm install redux-thunk
在store.js文件中引入redux-thunk以及
applyMiddleware(中间件)
;
// 该文件用于创建store,整个应用只有一个store对象
import { createStore, applyMiddleware } from 'redux'
import combineReducers from './reducer'
import thunk from 'redux-thunk' // 引入redux-thunk用于实现异步操作
export default createStore(combineReducers, applyMiddleware(thunk))
在action中封装异步操作,一般是写完异步逻辑后,调用同步action
export const incrementAction = (data) => ({type: 'increment', data}) // 返回一个对象
export const decrementAction = (data) => ({type: 'decrement', data}) // 返回一个对象
export const incrementAsync = (data) => {
return (dispatch) => {
setTimeout(() => {
dispatch(incrementAction(data))
}, 500)
}
} // 返回一个对象
其余逻辑与上面讲的相同,可自行编写~
此种异步方法可酌情使用(反正我不想这样用,麻烦哈哈哈哈)~
Redux与React-Redux的区别
react-redux利用容器组件与ui组件的父子关系实现数据和方法的使用;
原生redux确实使用原生store.getState()和store.dispatch()方法实现数据和方法的使用(哈哈哈,像是废话~)
redux开发工具的使用
需安装插件Redux-DevTools,配合redux-devtools-extention库使用;
npm install redux-devtools-extention
并配置于创建store的store.js文件中,
import {composeWithDevTools} from 'redux-devtools-extension'
const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))
则启动项目后按F12可看到有Redux选项~
恭喜你看到了这里,又get到一项知识~bye
更多前端知识欢迎来首页查看哦~~