一个组件是否能同时发布和订阅?一个组件是否能同时订阅多个数据?(以函数式组件为例)
1.发布和订阅的一般操作流程
- 安装包 npm install pubsub-js
- 组件A想获取到组件B的消息C,发布订阅可以不用考虑组件AB的关系(父子、兄弟、祖孙等),
- 组件A,在刚挂载结束,就进行消息订阅,Pubsub.subscribe("C",(msg, data) => {console.log(msg,data)}
- 组件B,在获取到数据时,就进行消息发布,Pubsub.publish("C", {class:value,option:props.option});
- 当组件A检测到C发生变化,组件A中就拿到了数据,并进行数据处理,或发送请求或发送别的。这个监测就用到了useEffects
2.useEffect
- useEffect用来处理副作用,什么是副作用?什么是纯的?简单来说,纯的就是传入了a,b两个参数,那么这个纯的就不能修改外部数据或者依赖外部数据且只能作a与b的计算;副作用就是在很多情况下除了处理传入参数a、b,还可能修改局部变量、dom、console.log()等等。
- useEffect的处理时机可以看做 react类组件 中
componentDidMount(刚挂载结束)
,componentDidUpdate(组件更新后)
和componentWillUnmount(组件将要卸载)
这三个生命周期函数的组合。useEffect()有两个参数,第一个参数是要执行的函数,第二个参数是一个依赖项数组(根据需求第二个参数可选择性填写),根据数组里的变量是否变化决定是否执行函数。第二个参数不写,页面刷新一次,useEffect中的函数就会刷新一次;第二个参数为空数组[],useEffect中的函数只执行一次;如果有变量,该变量发生变化就执行一次。
useEffect(() => { // 订阅消息,另外两个产生数据的组件里发布数据 var token = Pubsub.subscribe("conditionData", async (msg, data) => { setCD(data); console.log(msg, data); // 向后端发送请求获取数据,然后传递给父组件 try { const response = await reqSearchStudent( { data: data, }); console.log("请求成功", response); if (response.data.status === 0) { alert(response.data.msg) } else if (response.data.status === 1) { console.log(response.data.docs); response.data.docs.key = 1; setTabData(response.data.docs) } } catch (error) { console.log("请求失败", error); } }) return () => Pubsub.unsubscribe(token) }, [conditionData])
3.一个组件是否可以既订阅又发布呢?
场景:组件A要订阅组件B时,B又要订阅组件A,A要用B的数打印,B要用A的数据打印
是可以的,在整个实验过程中,A组件和B组件都能获取到对方发布的数据,代码如下:
//组件A
import React, { useEffect, useState } from 'react' import PubSub from 'pubsub-js' export default function A() { const [b,setB] = useState(0); // useEffect用来检测b变动,变动就打印数据 useEffect(()=>{ // 订阅消息b let token = PubSub.subscribe('b',(msg,data)=>{ setB(data); console.log('a监测到b数据变化了') console.log(msg,data) }) return ()=>PubSub.unsubscribe(token) },[b]) const changeA = ()=>{ const a = document.getElementById('a'); let c = parseInt(a.value) + b; a.value = c; // 发布数据 PubSub.publish('a',c); } return ( <div> <input type="text" id='a'/> <button onClick={changeA}>点击</button> </div> ) }//组件B
import React, { useEffect, useState } from 'react' import PubSub from 'pubsub-js' export default function B() { const [a,setA] = useState(1); // useEffect用来检测b变动,变动就打印数据 useEffect(()=>{ // 订阅消息b let token = PubSub.subscribe('a',(msg,data)=>{ console.log('b监测到a数据变化了') setA(data); console.log(msg,data) }) return ()=>PubSub.unsubscribe(token) },[a]) const changeB = ()=>{ const b = document.getElementById('b'); let c = parseInt(b.value) - a; b.value = c; // 发布数据 PubSub.publish('b',c); } return ( <div> <input type="text" id='b'/> <button onClick={changeB}>点击</button> </div> ) }4.一个组件能否同时订阅多个组件的数据
场景:Test同时订阅组件A与组件B的数据 可以
import React from 'react' import A from './A' import B from './B' import { useState,useEffect } from 'react' import PubSub from 'pubsub-js' export default function Test() { const [b,setB] = useState(0); const [a,setA] = useState(0); // useEffect用来检测b变动,变动就打印数据 useEffect(()=>{ // 订阅消息b let tokenA = PubSub.subscribe('a',(msg,data)=>{ setA(data); console.log('T监测到a数据变化了') console.log(msg,data) })
//这里如果不取消订阅,那么每次刷新页面,触发都会产生新的token,组件也会被多执行 return ()=>{PubSub.unsubscribe(tokenA)} },[a])useEffect(()=>{ // 订阅消息b let tokenB = PubSub.subscribe('b',(msg,data)=>{ setB(data); console.log('T监测到b数据变化了') console.log(msg,data) })
//这里如果不取消订阅,那么每次刷新页面,触发都会产生新的token,组件也会被多执行 return ()=>{PubSub.unsubscribe(tokenB);} },[b])const changeT = ()=>{ const t = document.getElementById('t'); let c = parseInt(t.value) + b + a; t.value = c; // // 发布数据 // PubSub.publish('t',c); } return ( <div> <A/> <hr /> <B/> <hr/> <input type="text" id='t' /> <button onClick={changeT}>点击</button> </div> ) }效果: