React在组件中如何监听redux中state状态的改变
目录
- 在组件中监听redux中state状态的改变
- 解决方式
- React和redux的状态处理
在组件中监听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="./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和自动封装无状态组件为有逻辑的组件,这种情况下我们只要写无状态组件,省了很多工作量。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。