Comunicación de componentes en React 02: suscripción y publicación de mensajes, cancelación de suscripción y cancelación de suscripción al desinstalar un componente

1. Introducción

1.1 Comunicación mediante accesorios

  • El artículo anterior introdujo el uso de accesorios para la comunicación entre componentes, pero usar accesorios para la comunicación entre niños y hermanos no es la mejor opción, por lo que introduciremos la suscripción y publicación de mensajes.
  • Con respecto a los accesorios, puede leer el siguiente artículo:
    Comunicación de componentes en React 01—props .

1.2 Acerca del usoEfecto

  • Se utilizará al escribir mensajes de suscripción a continuación, así que aquí hay una breve introducción:
  • El uso de useEffect puede ser equivalente al ciclo de vida en el componente de clase y puede reemplazarseEl componente está montado (componentDidMount)Componente actualizado (componentDidUpdate)El componente desinstalará estos tres ganchos (componentWillUnmount)
    • 1⃣️El segundo parámetro de useEffect es 空数组el caso. La función en el primer parámetro es equivalente a la función en el componente de clase.Gancho de finalización de montaje de componentes (componentDidMount).
      En este momento, puedes crear temporizadores, suscribirte a mensajes, etc.
    • 2⃣️Si se usa el segundo parámetro de useEffect 不传 或者 是非空数组, entonces el primer parámetro es equivalente aGancho actualizado del componente (componentDidUpdate)
      • No aprobado: monitoree cada atributo en el estado del componente y llámelo cada vez que haya una actualización;
      • Matriz no vacía: puede especificar una o varias propiedades en el estado de monitoreo y se llamará solo cuando se actualicen las propiedades monitoreadas.
    • 3⃣️useEffect El primer parámetro no puede tener valor de retorno, pero si lo hayfunción de retorno, entonces esta función de retorno es equivalente a la del componente de claseEl gancho para que el componente se desmonte (componentWillUnmount).
      Generalmente se utiliza para cancelar temporizadores, cancelar suscripciones, etc.

2. Instale pubsub-js

  • El comando es el siguiente:
    npm install pubsub-js
    

3. Suscripción y publicación de mensajes.

3.1 Ejemplo simple-1

  • Diseño para pequeñas necesidades:
    Insertar descripción de la imagen aquí
  • Diseño e implementación de código.
    • ChildA——mensaje de publicación.
      El código principal tiene solo 2 líneas:
      import PubSub from 'pubsub-js'
      
      //PubSub.publish('MY TOPIC', 'hello world!');
      PubSub.publish('GamesNews','通知:在我校(ChildA)举办运动会的时间定于10月16日');
      
      Insertar descripción de la imagen aquí
    • ChildB: se suscribe a mensajes (con la ayuda de useEffectganchos), el código principal es el siguiente:
      import PubSub from 'pubsub-js'
      
          //订阅运动会消息
      const subscriberGamesNew = function(msg, data){
              
              
          console.log('ChildB 订阅的消息--subscriberGamesNew---');
          console.log( msg, data );//msg-订阅的topic  data-消息内容
      }
      
      useEffect(()=>{
              
              
          //subscribe-订阅的方法   'GamesNews'-订阅的主题
          let token = PubSub.subscribe('GamesNews', subscriberGamesNew);
          console.log('token',token);
      },[])//这里第二个参数是空数组 [],这种情况相当于class组件中 "组件挂载完毕的钩子" 
      
      Insertar descripción de la imagen aquí
  • Mostrar resultados
    Insertar descripción de la imagen aquí

3.2 Ejemplo simple-2 (mejora, optimización): suscríbase a mensajes + use mensajes

  • Los pequeños requisitos son los siguientes:
    Insertar descripción de la imagen aquí
  • El diseño del código es el siguiente:
    • editor
      Insertar descripción de la imagen aquí
    • Abonado
      Insertar descripción de la imagen aquí
      Insertar descripción de la imagen aquí
      Insertar descripción de la imagen aquí
  • El efecto es el siguiente:
    Insertar descripción de la imagen aquí

4. Darse de baja

4.1 Cancelar un solo tema

  • gramática:

    const token1 = PubSub.subscribe('GamesNews', mySubscribers);//订阅 GamesNews
    
    //取消订阅
    PubSub.unsubscribe(token1);
    或
    PubSub.unsubscribe('GamesNews');
    
  • Los ejemplos son los siguientes:
    Insertar descripción de la imagen aquí

  • El efecto es el siguiente:
    Insertar descripción de la imagen aquí

  • La función anterior se puede optimizar y cancelar según el tema, de la siguiente manera:

     const myUnsubscribe =(topic)=>{
          
          
         PubSub.unsubscribe(topic); //取消订阅的GamesNews
         console.log('取消订阅运动会消息---成功!!!');
     }
    
    <button onClick={
          
          ()=>myUnsubscribe('GamesNews')}>取消订阅运动会消息</button>
    

4.2 Cancelar múltiples o más gramáticas

4.3 Darse de baja al desinstalar un componente

4.3.1 Desinstalar todos los componentes

  • En primer lugar, el código para desinstalar todos los componentes se proporciona de la siguiente manera:
    Insertar descripción de la imagen aquí
    El código principal es solo este, no entraré en detalles, compruébelo usted mismo.
    import root from '../index';
    
        //卸载组件---卸载所有
        const unMountAll =()=>{
          
          
            //卸载组件 root
            root.unmount();
        }
    
    
     <button onClick={
          
          unMountAll}>卸载所有组件</button>
    
  • Luego, mira el efecto:
    Insertar descripción de la imagen aquí
  • Finalmente, una breve explicación:
    • Para desinstalar un componente, en el ciclo de declaración del componente de clase, en realidad llama al gancho para que el componente se desinstale. En el componente de función, se puede reflejar en useEffect. Para obtener más detalles, consulte la introducción en 1.2 anterior.1.2 Acerca del usoEfecto》。
    • De hecho, al desinstalar arriba, si hay un código que enciende el temporizador pero no lo cancela, hay un problema. De hecho, también se puede decir que si solo se desinstala el componente B arriba, pero el componente B se ha suscrito mensajes, entonces si no es razonable desinstalar el componente B pero no cancelar la suscripción, esto también puede entenderse como parte de la optimización del front-end.
    • Solo digo que no puede ver el efecto, introduzcamos cómo desinstalar el componente B especificado para observar.

4.3.2 Desinstalar el componente especificado: cancelar la suscripción

  • 1⃣️ En el componente principal, controle la visualización del componente B (es decir: diseñe un botón para el componente B en el componente principal 卸载/渲染)
    Insertar descripción de la imagen aquí
  • 2⃣️ Se refleja en la función de retorno del primer parámetro en useEffect del componente B. Vea si la función de retorno se ejecuta cuando se desinstala el componente B.
    Insertar descripción de la imagen aquí
  • 3⃣️Ver el efecto
    Insertar descripción de la imagen aquí
  • Optimice y vea el efecto:
    entonces,Debe cancelar la suscripción al desinstalar el componente., la ubicación del código de baja es la siguiente:
    Insertar descripción de la imagen aquí
    Insertar descripción de la imagen aquí

5. Adjunto se encuentra el código central completo.

  • Estructura del código:
    Insertar descripción de la imagen aquí
  • código central
    • Aplicación.js + index.js
      Insertar descripción de la imagen aquí
    • Padre.jsx
      import React from "react";
      import ChildA from "./ChildA";
      import ChildB from "./ChildB";
      import './index.css'
      import root from '../index';
      
      function Parent() {
              
              
      
          const [mountChildBFlag,setMountChildFlag] = React.useState(true);
      
          //卸载组件---卸载所有
          const unMountAll =()=>{
              
              
              //卸载组件 root
              root.unmount();
          }
          return(
              <div className="parent">
                  我是父组件!
      
                  <div className="childA">
                      <ChildA notice={
              
              '通知——今天放假!'}/>
                  </div>
      
                  {
              
              /* <div className="childB">
                      <ChildB notice={'通知——今天放假!'} />
                  </div> */}
      
                  {
              
              /* 这里根据 mountChildBFlag 控制B组件的状态 */}
                  {
              
              
                      mountChildBFlag ? 
                      <div className="childB">
                          <ChildB notice={
              
              '通知——今天放假!'} />
                      </div>
                      : ""
                  }
      
                  <br /><br />
                  <button onClick={
              
              ()=>setMountChildFlag(!mountChildBFlag)}>卸载B组件/渲染B组件</button>
      
                  <br /><br />
                  <button onClick={
              
              unMountAll}>卸载所有组件</button>
                  
              </div>
          )
      }
      export default Parent;
      
    • NiñoA.jsx
      import React from "react";
      import PubSub from 'pubsub-js'
      
      function ChildA(props){
              
              
      
          const stuNameRef = React.useRef();
      
          //发布运动会消息 按钮触发
          function publishGamesNews(){
              
              
              // 发布运动会消息  topic-->GamesNews
              PubSub.publish('GamesNews','通知:在我校(ChildA)举办运动会的时间定于10月16日');
              console.log('-----ChildA 发布了 GamesNews 消息----');
          }
          // 发布学生消息  开除的学生
          function expelStuSubmit(event){
              
              
              event.preventDefault();//非受控组件  只取表单数据,但阻止表单提交,实现页面无刷新
      
              const stuName = stuNameRef.current.value;
              PubSub.publish('stusInfo',{
              
              stuName:stuName,schoolName:'ChildA-School',stuState:'被开除'});
          }
      
          return(
              <div>
                  我是子组件A!!!
                  <br /><br />
                  收到来自于父组件的数据:{
              
              props.notice}
      
                  <br /><br />
                  <button onClick={
              
              publishGamesNews}>发布运动会消息</button>
      
                  <br /><br />
                  <form onSubmit={
              
              expelStuSubmit}>
                      学生姓名:<input type="text" ref={
              
              stuNameRef} name="stuName"/>
                      <button>开除学生</button>
                  </form>
              </div>
          )
      }
      
      export default ChildA;
      
    • NiñoB.jsx
      import PubSub from 'pubsub-js'
      import {
              
               useEffect,useState } from 'react';
      
      function ChildB(props){
              
              
      
          const [gamesNews,setGamesNews] = useState('等通知……');
          const [stusInfo,setStuInfo] = useState(
              [
                  {
              
              stuName:'学生1',schoolName:'ChildA-School',stuState:'在校'},
                  {
              
              stuName:'学生2',schoolName:'ABC学校',stuState:'离校'},
                  {
              
              stuName:'张三',schoolName:'ChildA-School',stuState:'在校'},
                  {
              
              stuName:'李四',schoolName:'XXX附属中学',stuState:'托管'},
                  {
              
              stuName:'王五',schoolName:'ChildA-School',stuState:'在校'},
              ]
          );
      
          //我的订阅方法
          const mySubscribers = function(msg, data){
              
              
              console.log('ChildB 订阅的消息--mySubscribers---');
              // console.log( msg, data );//msg-订阅的topic  data-消息内容
              //将订阅到的新消息进行更新
              if('GamesNews'===msg){
              
              
                  console.log('订阅到运动会的消息是:',data);
                  setGamesNews(data);
              }else if('stusInfo'===msg){
              
              
                  console.log('订阅到开除的学生是:',data);
                  // const newStuInfo = [...stusInfo,data];//这个不去重,追加数据
                  //这个地方需要注意stusInfo 和 data的类型
                  const newStuInfo = stusInfo.map((stu)=>{
              
              
                      return data.stuName===stu.stuName ? data : stu;
                  });
                  setStuInfo(newStuInfo);
              }
          }
      
          useEffect(()=>{
              
              
              //subscribe-订阅的方法  
              const token1 = PubSub.subscribe('GamesNews', mySubscribers);//订阅 GamesNews
              const token2 = PubSub.subscribe('stusInfo', mySubscribers);// 订阅 stusInfo
              console.log('token1---',token1);
              console.log('token2---',token2);
      
              return ()=>{
              
              
                  //这个返回函数,相当于class中的“组件将要卸载的钩子”  在这里可以取消订阅
                  console.log('ChildB组件...被卸载了');
      
                  PubSub.unsubscribe(token1); //取消订阅
                  
              }
          },[])//这里第二个参数是空数组 [],这种情况相当于class组件中 "组件挂载完毕的钩子" 
      
          //取消订阅
          const myUnsubscribe =(topic)=>{
              
              
              PubSub.unsubscribe(topic); //取消订阅的GamesNews
              console.log('取消订阅运动会消息---成功!!!');
          }
      
          return(
              <div>
                  我是子组件B!!!
                  <br /><br />
                  收到来自于父组件的数据:{
              
              props.notice}
      
                  <br /><br /><br />
                  订阅1——运动会消息:{
              
              gamesNews}
                  <br />
                  <button onClick={
              
              ()=>myUnsubscribe('GamesNews')}>取消订阅运动会消息</button>
      
                  <br /><br /><br />
                  订阅2——学生消息:
                  <table>
                      <thead>
                          <tr>
                              <th>学生姓名</th>
                              <th>所在学校</th>
                              <th>状态</th>
                          </tr>
                      </thead>
                      <tbody>
                          {
              
              stusInfo.map((stu,index)=>{
              
              
                              return <tr key={
              
              index}>
                                  <td>{
              
              stu.stuName}</td>
                                  <td>{
              
              stu.schoolName}</td>
                                  <td>{
              
              stu.stuState}</td>
                              </tr>
                          })}
                      </tbody>
                  </table>
      
      
              </div>
          )
      }
      
      export default ChildB;
      
    • componente–>índice.css
      .parent{
          background-color: blueviolet;
          border: 1px solid;
          height: 900px;
          width: 600px;
          text-align: center;
      }
      
      .childA{
          background-color: green;
          height: 170px;
          margin: 20px;
      }
      
      .childB{
          background-color: grey;
          height: 400px;
          margin: 20px;
      }
      

Supongo que te gusta

Origin blog.csdn.net/suixinfeixiangfei/article/details/132976539
Recomendado
Clasificación