在react中,如果我们要实现任意组件之间的通信,我们可以通过redux实现。 在介绍redux之前,我们可以通过EventHub来实现一个redux来帮助我们理解。
首先,我们来看一下我们代码的结构,
容器内有A B两个组件,
A组件内有 C D 两个组件,
B组件内有 E F 两个组件。
代码如下
import React from 'react'
import ReactDOM from 'react-dom'
import style from './style3.css'
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='App'>
<A/>
<B/>
</div>
)
}
}
class A extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='A'>
A
<C/>
<D/>
</div>
)
}
}
class B extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='B'>
B
<E/>
<F/>
</div>
)
}
}
class C extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='Son'>
C
</div>
)
}
}
class D extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='Son'>
D
</div>
)
}
}
class E extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='Son'>
E
</div>
)
}
}
class F extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='Son'>
F
</div>
)
}
}
const render = () => {
ReactDOM.render(<App/>, document.querySelector('#root'))
}
render()
//css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.App, .A, .B {
border: 1px solid black;
display: flex;
justify-content: center;
padding: 20px;
margin: 20px;
}
.A, .B {
flex-direction: column;
text-align: center;
}
.Son{
border: 1px solid black;
padding: 20px;
margin: 20px;
}
接下来我们假设容器内有100000元,当D组件消费时,其他所有的组件都可以实时更新金额。
const money = {
amount: 100000
}
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='App'>
money = {this.props.money.amount}
<A money={this.props.money}/>
<B money={this.props.money}/>
</div>
)
}
}
const render = () => {
ReactDOM.render(<App money={money}/>, document.querySelector('#root'))
}
render()
我们可以将money通过props的方式层层传递,最后形成以下图
EventBus
接下来,为了实现一个组件消费,其他组件实时更新,我们需要一个EventHub来实现订阅发布模式。
const lists = {}
const EventHub = {
on(eventName, fn) {
if (!lists[eventName]) {lists[eventName] = []}
lists[eventName].push(fn)
},
trigger(eventName, data) {
if (!lists[eventName]) {return false}
lists[eventName].map(item => item(data))
}
}
我们通过Event.on 监听事件,然后push一个函数
在通过Event.trigger 触发事件,将data传入,执行函数
管家
接下来,我们还需要一个管家来监听事件
const steward = {
init(){
EventHub.on('花钱',(data)=>{
money.amount -= data
render()
})
}
}
steward.init()
我们的管家需要监听'花钱'事件,然后将剩余金额算出来,并重新render实现全局更新数据。
之后,我们就可以在组件D中,触发事件了
class D extends React.Component {
constructor(props) {
super(props);
}
x=()=>{
EventHub.trigger('花钱',100)
}
render() {
return (
<div className='Son'>
D
money={this.props.money.amount}
<button onClick={this.x}>花钱</button>
</div>
)
}
}
此时,我们就实现了任意组件之间的通信了
//全部代码
import React from 'react'
import ReactDOM from 'react-dom'
import style from './style3.css'
const money = {
amount: 100000
}
const lists = {}
const EventHub = {
on(eventName, fn) {
if (!lists[eventName]) {
lists[eventName] = []
}
lists[eventName].push(fn)
},
trigger(eventName, data) {
if (!lists[eventName]) {
return false
}
lists[eventName].map(item => item(data))
}
}
const steward = {
init() {
EventHub.on('花钱', (data) => {
money.amount -= data
render()
})
}
}
steward.init()
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='App'>
money = {this.props.money.amount}
<A money={this.props.money}/>
<B money={this.props.money}/>
</div>
)
}
}
class A extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='A'>
A
money = {this.props.money.amount}
<C money={this.props.money}/>
<D money={this.props.money}/>
</div>
)
}
}
class B extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='B'>
B
money = {this.props.money.amount}
<E money={this.props.money}/>
<F money={this.props.money}/>
</div>
)
}
}
class C extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='Son'>
C
money={this.props.money.amount}
</div>
)
}
}
class D extends React.Component {
constructor(props) {
super(props);
}
x = () => {
EventHub.trigger('花钱', 100)
}
render() {
return (
<div className='Son'>
D
money={this.props.money.amount}
<button onClick={this.x}>花钱</button>
</div>
)
}
}
class E extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='Son'>
E
money={this.props.money.amount}
</div>
)
}
}
class F extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='Son'>
F
money={this.props.money.amount}
</div>
)
}
}
const render = () => {
ReactDOM.render(<App money={money}/>, document.querySelector('#root'))
}
render()
redux
redux和EventHub的原理基本上是一样的
redux有以下几个关键内容,分别和EventHub对应
| redux | 作用 | EventHub |
|---|---|---|
| store | 存储数据 | money |
| reducer | 存储eventname,执行操作 | steward |
| dispatch 中的 type | 触发事件 | trigger中的eventname |
| dispatch 中的 payload | 触发事件时传的数据 | trigger中的data |
| subscribe | 数据一旦有变化就重新渲染 | steward中的render |
- redux的引入
yarn add redux
- 创建store reducer
import {createStore} from "redux"
const reducer = (state, action) => {
state = state || {money: {amount: 100000}}
switch (action.type) {
case '花钱':
return {
money: {amount: state.money.amount - action.payload}
}
default:
return state
}
}
const store =createStore(reducer)
- 触发事件
class D extends React.Component {
constructor(props) {
super(props);
}
x = () => {
store.dispatch({type: '花钱', payload: 100})
}
render() {
return (
<div className='Son'>
D
money={this.props.money}
<button onClick={this.x}>花钱</button>
</div>
)
}
}
- 订阅+重新渲染
const render = () => {
ReactDOM.render(<App store={store.getState()}/>, document.querySelector('#root'))
}
store.subscribe(render)
render()
完整代码如下
import React from 'react'
import ReactDOM from 'react-dom'
import style from './style3.css'
import {createStore} from "redux"
const reducer = (state, action) => {
state = state || {money: {amount: 100000}}
switch (action.type) {
case '花钱':
return {
money: {amount: state.money.amount - action.payload}
}
default:
return state
}
}
const store = createStore(reducer)
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='App'>
money = {this.props.store.money.amount}
<A money={this.props.store.money.amount}/>
<B money={this.props.store.money.amount}/>
</div>
)
}
}
class A extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='A'>
A
money = {this.props.money}
<C money={this.props.money}/>
<D money={this.props.money}/>
</div>
)
}
}
class B extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='B'>
B
money = {this.props.money}
<E money={this.props.money}/>
<F money={this.props.money}/>
</div>
)
}
}
class C extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='Son'>
C
money={this.props.money}
</div>
)
}
}
class D extends React.Component {
constructor(props) {
super(props);
}
x = () => {
store.dispatch({type: '花钱', payload: 100})
}
render() {
return (
<div className='Son'>
D
money={this.props.money}
<button onClick={this.x}>花钱</button>
</div>
)
}
}
class E extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='Son'>
E
money={this.props.money}
</div>
)
}
}
class F extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='Son'>
F
money={this.props.money}
</div>
)
}
}
const render = () => {
ReactDOM.render(<App store={store.getState()}/>, document.querySelector('#root'))
}
store.subscribe(render)
render()
redux的优点:
- 收敛eventname,便于管理
- 通过props传递store 虽然由于js的特性无法做到避免在组件内部修改store中的数据,大门还是在提醒我们不要随意修改store