在组件中监听redux中state状态的改变

解决方式

1、在组件中引入store

2、在constructor构造器方法中,重写store.subscribe方法(该方法即是监听state状态改变的放过)

组件完整代码如下: 

import React, { Component } from 'react'
import CSSModules from 'react-css-modules' 
import { connect } from 'react-redux'
import store from '../../redux/store' 
import styles from './BgMusic.css'
 
@CSSModules(styles)
class BgMusic extends Component {
  // 构造器
  constructor(props) {
    super(props)
    console.log('执行了constructor')
    // 监听state状态改变
    store.subscribe(() => {
      console.log('state状态改变了,新状态如下')
      console.log(store.getState())
      const state = store.getState()
      if (state.music.play) {
        // 播放背景音乐
        this.audio1.play()
      }
      else {
        // 暂停背景音乐
        this.audio1.pause()
      }
    })
  }
  render() {
    return (
      <div className={styles.container}>
        <audio ref={audio1 => { this.audio1 = audio1 }} className={styles.hidden} autoPlay="autoplay" controls="controls" loop="loop" preload="auto" src="https://www.atool.online/article/music/music.mp3">
            你的浏览器版本太低,不支持audio标签
        </audio>
      </div>
    )
  }
}
export default connect(
  // 这里的state,就是公共容器中的state,而不是当前组件的state。在这里定义了之后,在当前组件中,就可以通过this.props.music拿到该对象
  state => ({ music: state.music }),
)(BgMusic)

React和redux的状态处理

我们知道react中state是组件更新的唯一指标,并且只能通过组件的this.setState方法触发组件的重新渲染。这种形式导致了一个组件A想要触发另一个组件B更新,就必须触发组件B内部的this.setState。一般是通过一开始就在B中设置委托到组件A中。

例如: 

class B extends React.Component{
    state={key:"value"}
    handle(){
        this.setState({key:"newvalue"})
    }
    render(){
        return <div> 
                <A onOk=>{this.handle.bind(this)}/>
                <span>{this.state.key}</span>
            </div>
    }
}
class A extends React.Component{
    render(){return <button onClick={this.props.onOk}>click</button>}
}

这样也就隐形的要求B组件必须是A组件的父组件,换句话说:如果一个组件想要触发另一个组件的更新,需要触发者是被触发者的子组件。 父组件可以将更新的函数预先定好,作为属性传入子组件中,这样子组件中调用这个属性函数就触发了父组件的更新,本质是父组件将自己的一个函数委托给子组件处理。

当组件变得又多又复杂的时候,可能需要跨越好多层父子关系来传递这个闭包,这使得状态的管理非常复杂。

这里写图片描述

例如这种情况下,C想要触发A.setState,那就需要A先封好闭包作为属性传给B,B再传给C,C在合适的时机调用。调用完了,A的setState会引起所有的子组件重新render。

如果C想要触发D的更新,则也需要A作为中介,将D中要更新的部分拿出来,作为props由A来传入,这样还是按照之前的做法,C可以引起A的render,进而导致了所有组件render,也就包括了D。不过其实我们只想要D更新,其他组件并不需要更新。而且我们看到state的存储很乱,有时候我们将state存到本组件中,由自己掌握更新的时机,有时候需要交给父组件来掌握,此时子组件是无状态的,所有数据由父组件通过props传入。

这种方式无论从闭包传递还是过多的组件render上都是不好的,我们思考能不能通过更高效的方式完成这件事。首先是闭包传递,其实本质上是A把更新这件事放到一个函数中,然后把该函数作为属性传递给了子组件。我们可以这样来做,在A中设置一个事件监听器当事件触发的时候就更新状态,而在C中设置一个事件激发当合适的时机(如点击按钮)触发这个事件,这样就完成了直接触发另一个组件的更新。这样每个组件都有自己的state,并且都监听一个自己特定的事件,如果事件触发,就相应的调用setState完成自己的更新。

Redux就是这种思路,核心概念是store,所有组件ABCDE的state都存到了store.state中,这个变量只能通过触发action才能改变,并且专门定义了这种根据action更新store.state值的函数叫reducer。当然了改变了这个变量的值对我们整个react应用没有任何影响,还需要把这个值和每个组件内的state关联起来。每个组件中都有一个store.subcribe(func),即每个组件都可以监听这个store.state的变化,如果变化就触发这个函数,然后可以看变量中是不是和自己相关的例如可以在store中这样存储{a:xxx,b:xx,c:xx,d:xx}这样A只需要检查store.getState().a是不是有变。

如下:

这里写图片描述

上图中,其实ABCD的回调函数都会触发,只不过触发后有个判断,只有D的发生了变化,所以只有D进行后续setState和render操作。

Redux的思想是这样的,首先state全都交到store中来保存,每个组件订阅store的变化,一但发生变化,就把自己的state同步。store的变化由action这种方式唯一触发,管理起来也方便。不过Subscribe写起来太麻烦了,所以ReactRedux模块提供了Provider 和connect,可以很方便的完成自动Subscribe和自动封装无状态组件为有逻辑的组件,这种情况下我们只要写无状态组件,省了很多工作量。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持阿兔在线工具。

点赞(0)

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部