在react学习中,redux是比较难理解的一个点,今天我们就深入了解一下如何用redux来实现react-redux中connect函数从而便于理解和使用react-redux。
官方解释:redux 是 js 应用的可预测状态的容器。 可以理解为全局数据状态管理工具(状态管理机),用来做组件通信等。
当没有使用redux时兄弟组件间传值将很麻烦,代码很复杂冗余。使用redux
定义全局单一的数据Store,可以自定义Store里面存放哪些数据,整个数据结构也是自己清楚的。
action:事件,它本质上是JavaScript的普通对象,它描述的是“发生了什么”。action由type:string和其他构成。
reducer:一个监听器,只有它可以改变状态。是一个纯函数,它不能修改state,所以必须是生成一个新的state。在default情况下,必须返回旧的state。
store:一个类似数据库的存储(或者可以叫做状态树),需要设计自己的数据结构来在状态树中存储自己的数据。
首先看一下目录结构:
再看一下src/index.js中的代码结构:
import React, {Fragment} from 'react'
import Calculate from "./components/Calculate";
function App(props) {
return(
)
}
export default App;
进入store目录中的中查看src/store/index.js, store就是整个项目保存数据的地方,并且只能有一个。创建store就是把所有reducer给它。
//创建store对象
import {createStore} from 'redux'
import reducer from './reducer'
const store = createStore(reducer)
export default store
其中引入了reducer,接着查看src/store/reducer.js,
import {
INCREMENT,
DECREMENT
} from "./action-types";
const initState = {
count: 1
}
function change(state = initState, action) {
switch (action.type) {
case INCREMENT:{
return {...state, count: state.count + action.number}
}
case DECREMENT:{
return {...state, count: state.count - action.number}
}
default:{
return {...state}
}
}
}
export default change
这里因为只是演示,就直接export default了,其中引入了action-types中的命名,进入查看src/store/action-types.js
//简单导出命名
export const INCREMENT = 'INCREMENT'
export const DECREMENT = 'DECREMENT'
最后查看src/store/action.js中的代码结构, redux将每一个更改动作描述为一个action,要更改state中的内容,你需要发送action。一个action是一个简单的对象,用来描述state发生了什么变更。
import {
INCREMENT,
DECREMENT
} from "./action-types";
export function increment(number) {
return{
type: INCREMENT,
number
}
}
export function decrement(number) {
return{
type: DECREMENT,
number
}
}
假设在计数器组件Calculate中我们知道react-redux中connect函数的基本用法是:
const mapStateToProps = state => ({
count: state.count
})
const mapActionToDispatch = dispatch => ({
Increment(number){
dispatch(xxx)
},
Decrement(number){
dispatch(xxx)
}
})
export default connect(mapStateToProps, mapActionToDispatch)(Calculate);
由用法我们知道connect函数第一个和第二个参数都是函数,函数的返回值是一个对象,而connect函数的返回值是一个高阶组件,所以才能进行调用( 高阶组件是参数为组件,返回值为新组件的函数),而mapStateToProps中的state参数以及mapActionToDispatch中的dispatch参数从何而来呢?我们看一下自己写的connect函数:
import React from 'react'
import store from "./index";
function connect(mapStateToProps, mapActionToDispatch) {
return function (WrapComponent) { // connect函数返回值是高阶组件
return class extends React.Component{ // 高阶组件返回值是一个新的组件
constructor(props) {
super(props);
this.state = {
// store.getState() 获取state对象
storeState: mapStateToProps(store.getState())
}
}
componentDidMount() {
// 进行监听 一旦state中的属性值发生变化就调用setState来重新渲染
this.subscribe = store.subscribe(() => {
this.setState({
storeState: mapStateToProps(store.getState())
})
})
}
componentWillUnmount() {
// 取消监听
this.subscribe()
}
render() {
return(
)
}
}
}
}
export default connect
其中store.getState()就是获取state对象,store.dispatch就是用于派发action。
其中
{…mapActionToDispatch(store.dispatch)}/>
就是将props以及state和dispatch传递给高阶函数所返回的新组件,所以才能用props.increment()函数以及props.count属性。
在写完connect函数之后我们用一下试一试:
import React from 'react'
import connect from ".././store/connect";
import {
increment,
decrement
} from ".././store/actions";
function Calculate(props) {
const {count} = props
return(
{count}
)
}
const mapStateToProps = state => ({
count: state.count
}
)
const mapActionToProps = dispatch => ({
Increment(number){
dispatch(increment(number))
},
Decrement(number){
dispatch(decrement(number))
}
})
export default connect(mapStateToProps, mapActionToProps)(Calculate);
测试的结果也是没有问题的,以上就是我对在redux中手动实现connect函数的基本理解。