React在組件中如何監(jiān)聽(tīng)redux中state狀態(tài)的改變
在組件中監(jiān)聽(tīng)redux中state狀態(tài)的改變
解決方式
1、在組件中引入store
2、在constructor構(gòu)造器方法中,重寫(xiě)store.subscribe方法(該方法即是監(jiān)聽(tīng)state狀態(tài)改變的放過(guò))
組件完整代碼如下:
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 { ? // 構(gòu)造器 ? constructor(props) { ? ? super(props) ? ? console.log('執(zhí)行了constructor') ? ? // 監(jiān)聽(tīng)state狀態(tài)改變 ? ? store.subscribe(() => { ? ? ? console.log('state狀態(tài)改變了,新?tīng)顟B(tài)如下') ? ? ? console.log(store.getState()) ? ? ? const state = store.getState() ? ? ? if (state.music.play) { ? ? ? ? // 播放背景音樂(lè) ? ? ? ? this.audio1.play() ? ? ? } ? ? ? else { ? ? ? ? // 暫停背景音樂(lè) ? ? ? ? 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標(biāo)簽 ? ? ? ? </audio> ? ? ? </div> ? ? ) ? } } export default connect( ? // 這里的state,就是公共容器中的state,而不是當(dāng)前組件的state。在這里定義了之后,在當(dāng)前組件中,就可以通過(guò)this.props.music拿到該對(duì)象 ? state => ({ music: state.music }), )(BgMusic)
React和redux的狀態(tài)處理
我們知道react中state是組件更新的唯一指標(biāo),并且只能通過(guò)組件的this.setState方法觸發(fā)組件的重新渲染。這種形式導(dǎo)致了一個(gè)組件A想要觸發(fā)另一個(gè)組件B更新,就必須觸發(fā)組件B內(nèi)部的this.setState。一般是通過(guò)一開(kāi)始就在B中設(shè)置委托到組件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組件的父組件,換句話說(shuō):如果一個(gè)組件想要觸發(fā)另一個(gè)組件的更新,需要觸發(fā)者是被觸發(fā)者的子組件。 父組件可以將更新的函數(shù)預(yù)先定好,作為屬性傳入子組件中,這樣子組件中調(diào)用這個(gè)屬性函數(shù)就觸發(fā)了父組件的更新,本質(zhì)是父組件將自己的一個(gè)函數(shù)委托給子組件處理。
當(dāng)組件變得又多又復(fù)雜的時(shí)候,可能需要跨越好多層父子關(guān)系來(lái)傳遞這個(gè)閉包,這使得狀態(tài)的管理非常復(fù)雜。
例如這種情況下,C想要觸發(fā)A.setState,那就需要A先封好閉包作為屬性傳給B,B再傳給C,C在合適的時(shí)機(jī)調(diào)用。調(diào)用完了,A的setState會(huì)引起所有的子組件重新render。
如果C想要觸發(fā)D的更新,則也需要A作為中介,將D中要更新的部分拿出來(lái),作為props由A來(lái)傳入,這樣還是按照之前的做法,C可以引起A的render,進(jìn)而導(dǎo)致了所有組件render,也就包括了D。不過(guò)其實(shí)我們只想要D更新,其他組件并不需要更新。而且我們看到state的存儲(chǔ)很亂,有時(shí)候我們將state存到本組件中,由自己掌握更新的時(shí)機(jī),有時(shí)候需要交給父組件來(lái)掌握,此時(shí)子組件是無(wú)狀態(tài)的,所有數(shù)據(jù)由父組件通過(guò)props傳入。
這種方式無(wú)論從閉包傳遞還是過(guò)多的組件render上都是不好的,我們思考能不能通過(guò)更高效的方式完成這件事。首先是閉包傳遞,其實(shí)本質(zhì)上是A把更新這件事放到一個(gè)函數(shù)中,然后把該函數(shù)作為屬性傳遞給了子組件。我們可以這樣來(lái)做,在A中設(shè)置一個(gè)事件監(jiān)聽(tīng)器當(dāng)事件觸發(fā)的時(shí)候就更新?tīng)顟B(tài),而在C中設(shè)置一個(gè)事件激發(fā)當(dāng)合適的時(shí)機(jī)(如點(diǎn)擊按鈕)觸發(fā)這個(gè)事件,這樣就完成了直接觸發(fā)另一個(gè)組件的更新。這樣每個(gè)組件都有自己的state,并且都監(jiān)聽(tīng)一個(gè)自己特定的事件,如果事件觸發(fā),就相應(yīng)的調(diào)用setState完成自己的更新。
Redux就是這種思路,核心概念是store,所有組件ABCDE的state都存到了store.state中,這個(gè)變量只能通過(guò)觸發(fā)action才能改變,并且專(zhuān)門(mén)定義了這種根據(jù)action更新store.state值的函數(shù)叫reducer。當(dāng)然了改變了這個(gè)變量的值對(duì)我們整個(gè)react應(yīng)用沒(méi)有任何影響,還需要把這個(gè)值和每個(gè)組件內(nèi)的state關(guān)聯(lián)起來(lái)。每個(gè)組件中都有一個(gè)store.subcribe(func),即每個(gè)組件都可以監(jiān)聽(tīng)這個(gè)store.state的變化,如果變化就觸發(fā)這個(gè)函數(shù),然后可以看變量中是不是和自己相關(guān)的例如可以在store中這樣存儲(chǔ){a:xxx,b:xx,c:xx,d:xx}這樣A只需要檢查store.getState().a是不是有變。
如下:
上圖中,其實(shí)ABCD的回調(diào)函數(shù)都會(huì)觸發(fā),只不過(guò)觸發(fā)后有個(gè)判斷,只有D的發(fā)生了變化,所以只有D進(jìn)行后續(xù)setState和render操作。
Redux的思想是這樣的,首先state全都交到store中來(lái)保存,每個(gè)組件訂閱store的變化,一但發(fā)生變化,就把自己的state同步。store的變化由action這種方式唯一觸發(fā),管理起來(lái)也方便。不過(guò)Subscribe寫(xiě)起來(lái)太麻煩了,所以ReactRedux模塊提供了Provider 和connect,可以很方便的完成自動(dòng)Subscribe和自動(dòng)封裝無(wú)狀態(tài)組件為有邏輯的組件,這種情況下我們只要寫(xiě)無(wú)狀態(tài)組件,省了很多工作量。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
React使用hook如何實(shí)現(xiàn)數(shù)據(jù)雙向綁定
這篇文章主要介紹了React使用hook如何實(shí)現(xiàn)數(shù)據(jù)雙向綁定方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03詳解React-Router中Url參數(shù)改變頁(yè)面不刷新的解決辦法
這篇文章主要介紹了詳解React-Router中Url參數(shù)改變頁(yè)面不刷新的解決辦法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05react 下拉框內(nèi)容回顯的實(shí)現(xiàn)思路
這篇文章主要介紹了react 下拉框內(nèi)容回顯,實(shí)現(xiàn)思路是通過(guò)將下拉框選項(xiàng)的value和label一起存儲(chǔ)到state中, 初始化表單數(shù)據(jù)時(shí)將faqType對(duì)應(yīng)的label查找出來(lái)并設(shè)置到Form.Item中,最后修改useEffect,需要的朋友可以參考下2024-05-05React?+?Typescript領(lǐng)域初學(xué)者的常見(jiàn)問(wèn)題和技巧(最新)
這篇文章主要介紹了React?+?Typescript領(lǐng)域初學(xué)者的常見(jiàn)問(wèn)題和技巧,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06React中完整實(shí)例講解Recoil狀態(tài)管理庫(kù)的使用
這篇文章主要介紹了React中Recoil狀態(tài)管理庫(kù)的使用,Recoil的產(chǎn)生源于Facebook內(nèi)部一個(gè)可視化數(shù)據(jù)分析相關(guān)的應(yīng)用,在使用React的實(shí)現(xiàn)的過(guò)程中,因?yàn)楝F(xiàn)有狀態(tài)管理工具不能很好的滿(mǎn)足應(yīng)用的需求,因此催生出了Recoil,對(duì)Recoil感興趣可以參考下文2023-05-05ReactNative踩坑之配置調(diào)試端口的解決方法
本篇文章主要介紹了ReactNative踩坑之配置調(diào)試端口的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07詳解使用create-react-app添加css modules、sasss和antd
這篇文章主要介紹了詳解使用create-react-app添加css modules、sasss和antd,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07在create-react-app中使用css modules的示例代碼
這篇文章主要介紹了在create-react-app中使用css modules的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07