reduce是redux中用来管理state的地方。通俗一点他就是一个产生数据池的方法。而这个数据池就是可供众多组件共同访问的数据池,不需要组件之间传来传去。
当然reduce也有他自己的弊端,在接受到action指令后,他只能去根据指令来返回一个新的state,而不是直接去修改老的state。这就导致了如果state是一个对象或者是一个数组的时候,处理起来会很麻烦,因为我们不能去动原来的state,只能产生一个新的state。
例如当我们的state是一个数组的时候,这时有一个action指令是要往原先的state数组里添加一项新的数据。如果正常情况下,我们可以接收到这一项新数据之后,直接state.push(item),即可完成添加了。
但是因为reduce中,不允许去修改state,所以这个时候,我们就不得不采取别的方法,可以克隆出一个新数组,然后再去操作新数组。或者是用filter方法,直接产生一个新数组。
这样做真的麻烦,这点个人感觉vuex用起来就爽多了,可以直接去修改state中的数据。
当然事情还没这么简单,试想以下。如果我们这个state非常的庞大,是一个对象,对象里有各种数据类型的属性,有字符串,数值,对象,数组等等。这个时候如果我们接收到一个action,要去操作state中的某一个属性。那将会变得非常非常的麻烦。又不能动原来的state,又去修改state的属性。。。。这真的是头疼。
当然,redux给我们提供了一个方法combineReducers https://www.redux.org.cn/docs/recipes/reducers/UsingCombineReducers.html
这个方法是做什么用的呢?
他支持将多个reduce合并成一个,也就是说,你可以让你的每个reduce只为某一个数据,而不是一个数据的集合。借上文的例子,当state非常庞大的时候,就可以将他拆分成很多个reduce,这样每个reduce只负责他自己的变化,操作方便,简单了很多。combineReducers 方法的作用就是将这些reduc又合并起来,返回一个对象出来。方便你去取数据。
先来看看怎么使用combineReducers方法吧。
/**
* 包含多个reducer函数的模块
*/
import React from 'react'
export function counter(state = 0, action) {
switch (action.type) {
case 'add':
return state = action.data
case 'del':
return state = action.data
case 'change':
return state = action.data
default:
return state
}
}
export function newreduce(state = {name:'haha'},action) {
switch (action.type) {
case 1:
return
default:
return state
}
}
这里有两个state,一个是number类型的,一个是对象类型的。
接下来我们在创建store的文件里去合并以下这两个reduce
import {createStore,applyMiddleware,combineReducers} from 'redux'
import {counter,newreduce} from './redux/reducers'
import thunk from 'redux-thunk'
let mainReduce = combineReducers({counter,newreduce}) 这里调用combineReducers方法,传如一个对象,对象的属性就是要合并的reduce
const store = createStore(mainReduce,applyMiddleware(thunk)) 然后将combineReducers方法返回的东西作为reduce传入createStore方法
接下来在组件中打印以下store看看
可以看到两个reduce已经合并到一起去了,返回了一个新的对象。
下面看一个例子
上面是一个简单的用redux实现的demo,里面没有复杂的state,这个demo里的state就是一个number。但是借这个简单的例子来讲解以下combineReducers 如何在复杂的state中发挥作用
以下的代码都是基于connect链接之上的,不知道的可以移步上一篇文章https://www.jianshu.com/p/dce005ff1057
在使用了connect链接之后,我们的UI组件就不需要写redux代码了,UI组件中的状态统一由connect生成的容器组件传过来,如下
import React from 'react'
import {Component} from 'react'
import {add,del,addAsync} from './redux/actions'
import Child from "./component";
import PropTypes from 'prop-types'
//引入链接函数
import {connect} from 'react-redux'
class App extends Component {
constructor(porps) {
super(porps);
}
//声明接收的属性的类型
static propTypes = {
data:PropTypes.object.isRequired,
add:PropTypes.func.isRequired,
del:PropTypes.func.isRequired,
addAsync:PropTypes.func.isRequired,
}
inputChange = (e) => {
let count = this.props.data.counter
count = e.target.value ? e.target.value : null
this.props.add(count)
}
add = () => {
let count = this.props.data.counter
count++
this.props.add(count)
}
del = () => {
let count = this.props.data.counter
count--
this.props.del(count)
}
ifodd = () => {
let count = this.props.data.counter
if (count % 2 !== 0) {
count++
}
this.props.add(count)
}
timeadd = () => {
let count = this.props.data.counter
this.props.addAsync(count)
}
render() {
console.log(this.props)
let count = this.props.data.counter
return (
<div>
<h1>click {count} time</h1>
<input type='number' onChange={this.inputChange} value={count}/>
<button onClick={this.add}>+</button>
<button onClick={this.del}>-</button>
<button onClick={this.ifodd}>increment if odd</button>
<button onClick={this.timeadd}>increment async</button>
<Child/>
</div>
)
}
}
//将连接函数暴露出去,连接函数接受两个参数
/**
* connect
* 参数1:一个函数,里面返回state
* 参数2:action
*/
export default connect(
state=>({data:state}),
{add,del,addAsync}
)(App)
上述代码主要是展示以下页面结构代码,没参考的意义,重点在下面。
可以看到上述组件中有一个Child的子组件。那如果这个Child组件也想要去修改state的值该怎么办,总不能说app组件接收到的state和方法,再传给子组件吧,如果是这样就违背了集中管理这个初衷了。如果子组件还有他自己的子组件,这样一层一层的传,何必要用redux呢。
子组件获取redux的方法其实很简单,直接把他整成和app组件一样。通过connect将他和store链接起来就行了。这样两个组件都能访问到store。
import React from 'react'
import PropTypes from 'prop-types'
import {add} from "./redux/actions";
import {Component} from 'react'
import {connect} from 'react-redux'
class Child extends Component {
childrenAdd = () => {
this.props.add(15)
}
render() {
console.log(this.props, '孙子接受的state')
return (
<div>
<h1 onClick={this.childrenAdd}>孙子组件</h1>
</div>
);
}
}
export default connect(
state => ({data: state}),
{add}
)(Child)
我在父组件和子组件中分别都打印了以下props。看看结果
可以看到,我们给富组件传的data和方法都在,并且data里是包含两个reduce的对象。
而子组件中也是一样,我们传了一个add方法,他接受到了,data他也接收到了。并且值和父组件接收到的是一样的。
现在去操作以下data中的值,看看变化
我们点击子组件的时候,调用了接收过来的add方法,并且传了15进去。可以看到图中父组件的data中的counter也变成了15。
这就是子孙组件如何获取redux的值的方法