Componentización de Reac y comunicación de componentes.

1. Módulos y componentes y los conceptos de modularización y componenteización.

  1. Módulo: proporcione archivos JS con funciones específicas al mundo exterior para facilitar la reutilización de JS, simplificar JS, mejorar los datos de eficiencia de JS, operar datos (funciones) y exponer funciones privadas que desea exponer al mundo exterior (el tipo de datos expuestos es un objeto)
    2. Modularidad: describe el método de codificación del proyecto, es decir, los proyectos se escriben y organizan según módulos.
    3. Componente: una colección de códigos y recursos utilizados para lograr efectos funcionales de diseño específicos, incluidos html, css, js, recursos de imágenes, etc., como una colección de recursos en el área del encabezado de una página. : describe el método de codificación del proyecto, es decir
    , los proyectos implementados se escriben como componentes.

2. Introducción a la componenteización

(1) Los componentes de React son más flexibles y diversos que Vue y se pueden dividir en muchos tipos de componentes de diferentes maneras:

  • Según la forma en que se definen los componentes, se pueden dividir en: Componente funcional y Componente de clase;
  • Según si hay un estado dentro del componente que necesita ser mantenido, se puede dividir en: componente sin estado
    y componente con estado.
  • Según las diferentes responsabilidades de los componentes, se pueden dividir en: Componente de presentación y Componente contenedor
    ;

(2) Estos conceptos se superponen mucho, pero se centran principalmente en la separación de la lógica de datos y la visualización de la interfaz de usuario:

  • Los componentes de funciones, componentes sin estado y componentes de visualización se centran principalmente en la visualización de la interfaz de usuario;
  • Los componentes de clase, los componentes con estado y los componentes de contenedor se centran principalmente en la lógica de datos;

(3) Por supuesto, existen muchos otros conceptos de componentes: como componentes asíncronos, componentes de alto orden, etc.

3. Introducción a varios componentes.

(1) Componentes de clase

Requisitos de definición para componentes de clase.

	
 - 组件的名称是**大写字符开头**(无论类组件还是函数组件) 
 - 类组件需要继承自 React.Component 
 - 类组件必须实现render函数

Antes de ES6, los componentes de clase se podían definir a través del módulo create-react-class, pero el sitio web oficial actual recomienda que usemos definiciones de clase ES6.

Definir un componente usando la clase.

  • El constructor es opcional, generalmente inicializamos algunos datos en el constructor;
  • Lo que se mantiene en this.state son los datos dentro de nuestro componente.
  • El método render() es el único método que debe implementarse en el componente de clase.
//  AntdTest 组件名
export default class AntdTest extends Component {
    
    
  render() {
    
    
    return (
      <div>
        <Button type="primary">按钮</Button>
      </div>
    )
  }
}

Nota: El valor de retorno de la función de renderizado.
Cuando se llama a render, verificará los cambios de this.props y this.state y devolverá uno de los siguientes tipos

1.react 元素:div还是<MyComponent>均为 React 元素
2.数组或 fragments:使得 render 方法可以返回多个元素。
3.Portals:可以渲染子节点到不同的 DOM 子树中。
4.字符串或数值类型:它们在 DOM 中会被渲染为文本节点
5.布尔类型或 null:什么都不渲染

(2) Componentes funcionales

Los componentes de función son funciones definidas usando la función. Esta función devuelve el mismo contenido que la función de representación en los componentes de clase.

Características

  • No existe un ciclo de vida, también será actualizado y montado;
  • No, esto (instancia de componente);
  • Sin estado interno (estado);
// 函数类型的组件
export function Welcome1(props) {
    
    
  return <div>Welcome1, {
    
    props.name}</div>
}

La diferencia entre los componentes de función de React y los componentes de clase

(3) Componentes sin estado (componentes de visualización)

React logra cambios dinámicos locales en la página actualizando el estado . Luego, para algunos componentes que son solo para visualización, o algunos componentes atómicos, como una determinada fila en la lista, un cuadro de entrada, etc., puede usar componentes sin estado. Dado que no hay ningún estado dentro de un componente sin estado, también se puede escribir utilizando componentes funcionales. Incluso si la función es relativamente simple, puedes escribirla directamente usando funciones de flecha. Algunas bibliotecas de componentes de UI utilizan principalmente componentes sin estado .

Resumen conciso

  • Se utiliza principalmente para definir plantillas y recibir datos pasados ​​desde los accesorios del componente principal.
  • Utilice la expresión {props.xxx} para colocar accesorios en la plantilla.
  • Las plantillas sin estado deben mantener la pureza de la plantilla para facilitar la reutilización de los componentes.
//无状态组件
const Child = (props)=>(
  <input type="text" value={
    
    props.value} onChange={
    
    props.fun}/>
)
或
const PureComponent = (props) => (
    <div>
        //use props
    </div>
)

característica

  • Un componente sin estado no puede acceder a los métodos del ciclo de vida porque no requiere gestión del estado y del ciclo de vida del componente.
  • No se crearán instancias de los componentes sin estado [El proceso sin creación de instancias no necesita asignar memoria adicional, por lo que el rendimiento es mejor; de manera similar, debido a que no se crean instancias, esto también resulta en la imposibilidad de acceder a esto]

Nota: Los componentes de funciones y los componentes de visualización son componentes sin estado.

(4) Componentes con estado

Sobre la base de componentes sin estado, si el componente contiene estado internamente y el estado cambia con eventos o mensajes externos, esto constituye un componente con estado. Los componentes con estado suelen tener un ciclo de vida para activar actualizaciones de estado en diferentes momentos. Este tipo de componente también es el más utilizado al escribir lógica empresarial. El número de estados y el mecanismo del ciclo de vida del componente son diferentes según los diferentes escenarios empresariales.

generalizar

  • Se utiliza principalmente para definir la lógica de interacción y los datos comerciales.
  • Utilice la expresión de {this.state.xxx} para montar los datos comerciales en la instancia del componente contenedor y luego pasar los accesorios al componente de visualización, que recibe los accesorios y los coloca en la plantilla.
class StatefulComponent extends Component {
    
    

    constructor(props) {
    
    
        super(props);
        this.state = {
    
    
            //定义状态
        }
    }

    componentWillMount() {
    
    
        //do something
    }
  
    componentDidMount() {
    
    
        //do something
    }
    ... //其他生命周期

    render() {
    
    
        return (
            //render
        );
    }
}

Nota: Los componentes de clase y los componentes de contenedor son componentes con estado.

(5) Componentes del contenedor

En la práctica de proyectos específicos, nuestros datos de front-end habituales se obtienen a través de solicitudes Ajax, y los datos de back-end obtenidos también necesitan un procesamiento adicional. Para que la responsabilidad del componente sea más única, se introdujo el concepto de componente contenedor (Componente Contenedor). Colocamos la lógica de procesamiento y adquisición de datos en el componente contenedor para reducir aún más el acoplamiento de los componentes.

/ 容器组件
export default class CommentList extends Component {
    
    
  constructor(props) {
    
    
    super(props)
    this.state = {
    
    
      comments: [],
    }
  }
  componentDidMount() {
    
    
    var _this = this
    axios.get('/path/to/commentsApi').then(function (response) {
    
    
      _this.setState({
    
     comments: response.data })
    })
  }
  render() {
    
    
    return (
      <div>
        {
    
    this.state.comments.map((c, i) => (
          <Comment key={i} {...c} />
        ))}
      </div>
    )
  }
}

Por ejemplo , el componente contenedor anterior es responsable de obtener los datos del usuario y luego pasarlos al componente UserList en forma de accesorios para renderizar. El componente contenedor no representa nodos DOM específicos en la página, por lo que generalmente actúa como una fuente de datos . Muchos marcos de uso común utilizan actualmente este formulario de componente. Por ejemplo: connect() de React Redux, createContainer() de Relay, Container.create() de Flux Utils, etc.

(6) Componentes de la pantalla

Un componente que solo muestra información sobre algunos datos.

// 展示组件
function Comment({
    
     data }) {
    
    
  return (
    <div>
      {
    
    ' '}
      <p>{
    
    data.body}</p> <p> --- {
    
    data.author}</p>{
    
    ' '}
    </div>
  )
}

Componente de presentación versus componente contenedor

El componente contenedor es responsable de la adquisición de datos y el componente de visualización es responsable de mostrar información basada en accesorios.

4. Anidamiento de componentes

La idea central de la componenteización debería ser dividir los componentes en componentes pequeños y luego anidarlos para finalmente formar nuestra aplicación;
analicemos la lógica de anidamiento del siguiente código:

import React, {
    
     Component } from 'react';

function Header() {
    
    
  return <h2>Header</h2>
}

function Main() {
    
    
  return (
    <div>
      <Banner/>
      <ProductList/>
    </div>
  )
}

function Banner() {
    
    
  return <div>Banner</div>
}

function ProductList() {
    
    
  return (
    <ul>
      <li>商品1</li>
      <li>商品2</li>
      <li>商品3</li>
      <li>商品4</li>
      <li>商品5</li>
    </ul>
  )
}

function Footer() {
    
    
  return <h2>Footer</h2>
}

export default class App extends Component {
    
    
  render() {
    
    
    return (
      <div>
        <Header/>
        <Main/>
        <Footer/>
      </div>
    )
  }
}

Como se muestra en el código:
el componente de la aplicación es el componente principal de los componentes de encabezado, principal y pie de página; el
componente principal es el componente principal de los componentes de banner y lista de productos;

6. Comunicación de componentes

1) El componente principal se comunica con el componente secundario

La forma de pasar accesorios es agregar atributos al componente principal y pasar el valor al componente secundario en el formato this.props.xxx (los componentes de clase usan this.props.xxx; los componentes de función usan props.xxx).
Idea: el componente principal pasa el valor al componente secundario y el estado del componente principal se pasa al componente secundario a través de accesorios.

import React, {
    
     Component } from 'react'
export default class Correspond extends Component {
    
    
  render() {
    
    
    return (
      <div>
        <Chindren name="小白"></Chindren>
      </div>
    )
  }
}

2) El subcomponente se comunica con el componente principal.

Puede usar props + devolución de llamada (llamando a la función de devolución de llamada pasada por el componente principal).
La idea es que el componente secundario pase el mensaje al componente principal llamando al método pasado por el componente principal al componente secundario. Una vez que el componente principal recibe los parámetros, asigna el valor al estado del componente principal.

import React, {
    
     Component } from 'react'

function Chindren(props) {
    
    
  return <div>Welcome, {
    
    props.name}</div>
}
class Welcome extends Component {
    
    
  constructor(props) {
    
    
    super(props)
    this.state = {
    
    
      msg: this.props.toChildren,
    }
  }
  toParent = () => {
    
    
    // 通过props属性获取父组件的getdata方法,并将this.state值传递过去
    this.props.callback('早上好!') //子组件通过此触发父组件的回调方法
  }
  render() {
    
    
    return (
      <div>
        <button onClick={
    
    this.toParent}> 副官向上级打招呼</button>
      </div>
    )
  }
}
export default class Correspond extends Component {
    
    
  constructor(props) {
    
    
    super(props)
    this.state = {
    
    
      name: '副官',
      back: '',
    }
  }
  //用于接收子组件的传值方法,参数为子组件传递过来的值
  changeMsg = (val) => {
    
    
    //把子组件传递过来的值赋给this.state中的属性
    this.setState({
    
    
      back: val,
    })
  }
  render() {
    
    
    return (
      <div>
        {
    
    /* 子组件向父组件传参数 */}
        <div>上级:Welcome, {
    
    this.state.name}!</div>
        {
    
    this.state.back && <div>副高:{
    
    this.state.back}</div>}
        {
    
    /* 注意:子组件中props的回调函数名称 和 父组件传递添加的方法(如:callback) 需一致 */}
        <Welcome callback={
    
    this.changeMsg}></Welcome>
      </div>
    )
  }
}

Insertar descripción de la imagen aquí

3) Comunicación del componente hermano

Redux implementa y utiliza componentes principales (los accesorios se pasan capa por capa).
La idea de pasar valores entre componentes hermanos es a través del componente principal. El proceso es el componente A - transferencia de valor -> componente principal. - transferencia de valor --> Componente B

import React, {
    
     Component } from 'react'

// Acls组件
class Acls extends Component {
    
    
  //按钮点击事件,向父组件传值
  handleClick() {
    
    
    this.props.data('hello...React...')
  }
  render() {
    
    
    return (
      <div>
        <button onClick={
    
    this.handleClick.bind(this)}>
          Acls组件中获取数据
        </button>
      </div>
    )
  }
}
//Bcls组件
class Bcls extends React.Component {
    
    
  render() {
    
    
    return <div>在Bcls组件中展示数据:{
    
    this.props.mess}</div>
  }
}

export default class Correspond extends Component {
    
    
  constructor(props) {
    
    
    super(props)
    this.state = {
    
    
      mess: '',
    }
  }

  //向子组件A 组件 提供的传值方法,参数为获取的子组件传过来的值
  getDatas(data) {
    
    
    this.setState({
    
    
      mess: data,
    })
  }
  render() {
    
    
    return (
      <div>
        {
    
    /* 兄弟组件传值 */}
        <Acls data={
    
    this.getDatas.bind(this)}></Acls>
        <Bcls mess={
    
    this.state.mess}></Bcls>
      </div>
    )
  }
}

4) Componente cruzado (como la comunicación entre abuelo y nieto)

Hay dos métodos comúnmente utilizados: paso de valores capa por capa y paso de valores entre capas.
A. Pase los valores capa por capa.
Primero comuníquese con el padre y el hijo, luego comuníquese con el hijo y el "nieto". El nivel de aprobación se convierte en abuelo->niño->"nieto". De la misma manera, los accesorios se transmiten de padres a hijos y Se cargan devoluciones de llamada.
B. Transferencia de valor entre capas

Los componentes pueden utilizar Context para la comunicación entre niveles.

La documentación oficial de React explica el contexto:
en una aplicación típica de React, los datos se pasan de arriba a abajo (de padre a hijo) a través del atributo props, pero este enfoque no es adecuado para ciertos tipos de propiedades. Extremadamente engorroso (por ejemplo, preferencias locales, Temas de interfaz de usuario), estas propiedades son requeridas por muchos componentes de la aplicación. El contexto proporciona una manera de compartir dichos valores entre componentes sin tener que pasar accesorios explícitamente a través de cada nivel del árbol de componentes
.
En una oración, se puede resumir como: transferencia de valor entre niveles y intercambio de estado .

Hay dos roles en este modo: Proveedor y Consumidor.
El Proveedor son componentes externos y se utilizan para proporcionar datos; cuando los datos se necesitan internamente, el Consumidor se utiliza para leerlos.

Abuelo——》nieto
  1. Cree un nuevo archivo context.js (en el mismo nivel que el componente principal), el valor predeterminado es un objeto
// 跨级传值  上下文
import React from 'react'
const MyContext = React.createContext({
    
     text: 'luck' })
export default MyContext

  1. Escribir un componente principal: introduzca contexto en el componente principal y utilice un proveedor para pasar el valor actual al siguiente árbol de componentes, donde valor es el valor pasado.
import React, {
    
     Component } from 'react'
import MyContext from './context'
import Grandson from './Grandson'

// 子组件
class Children extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        <Grandson></Grandson>
      </div>
    )
  }
}
export default class Correspond2 extends Component {
    
    
  // 使用一个 Provider 来将当前的 value 传递给以下的组件树。
  // 无论多深,任何组件都能读取这个值。
  render() {
    
    
    return (
      <div
        style={
    
    {
    
    
          backgroundColor: '#f7ba2a',
          padding: '20px',
          width: '500px',
          margin: 'auto',
          textAlign: 'center',
        }}
      >
        <p>父组件</p>
        {
    
    /* 对父组件:引入context,使用一个 Provider 来将当前的 value 传递给以下的组件树,value为传递的值。 */}
        <MyContext.Provider value={
    
    {
    
     text: '你好' }}>
          <Children></Children>
        </MyContext.Provider>
      </div>
    )
  }
}

  1. Componente nieto Grandson.js: también es necesario introducir contexto y agregar contexto estático = MyContext dentro del componente. En este momento, el valor pasado por el proveedor más cercano en la capa superior se puede obtener directamente a través de this.context. En este momento , this.context = {text:buena suerte}, es decir, el componente abuelo pasa valor.
import React from 'react'
import MyContext from './context'

class Grandson extends React.Component {
    
    
  //  孙组件: 同样需引入context,在组件内部添加static contextType = MyContext,
  //   此时将能通过this.context直接获取到上层距离最近的Provider传递的值,此时this.context = {
    
    text:good luck},即父组件传递value。
  static contextType = MyContext
  render() {
    
    
    return (
      <div
        style={
    
    {
    
    
          backgroundColor: '#13ce66',
          padding: '10px',
          width: '200px',
          margin: 'auto',
          marginTop: '20px',
        }}
      >
        <p>孙组件:</p>
        <span style={
    
    {
    
     color: 'blue' }}>{
    
    this.context.text}</span>
      </div>
    )
  }
}

export default Grandson

Obtenga el valor pasado a través de this.context.text
Insertar descripción de la imagen aquí

Sol——》El abuelo pasa el valor mediante devolución de llamada.
  1. Modifique el componente abuelo por valor, agregue un atributo al objeto pasado y vincule el método del componente abuelo value={ { text:'good luck',toParent:this.fromGranson}}
import React, {
    
     Component } from 'react'
import MyContext from './context'
import Grandson from './Grandson'

// 子组件
class Children extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        <Grandson></Grandson>
      </div>
    )
  }
}
export default class Correspond2 extends Component {
    
    
  // 使用一个 Provider 来将当前的 value 传递给以下的组件树。
  // 无论多深,任何组件都能读取这个值。
  constructor(props) {
    
    
    super(props)
    this.state = {
    
    
      msg: '',
    }
  }
  fromGranson = (val) => {
    
    
    this.setState({
    
    
      msg: val,
    })
  }
  render() {
    
    
    return (
      <div
        style={
    
    {
    
    
          backgroundColor: '#f7ba2a',
          padding: '20px',
          width: '500px',
          margin: 'auto',
          textAlign: 'center',
        }}
      >
        <p>祖父组件</p>
        <span style={
    
    {
    
     color: 'red' }}>{
    
    this.state.msg}</span>
        {
    
    /* 对父组件:引入context,使用一个 Provider 来将当前的 value 传递给以下的组件树,value为传递的值。 */}
        <MyContext.Provider
          value={
    
    {
    
     text: '你好', toParent: this.fromGranson }}
        >
          <Children></Children>
        </MyContext.Provider>
      </div>
    )
  }
}

  1. Componente Sun: agregar un botón, vincular método, ejecutar devolución de llamada de función
import React from 'react'
import MyContext from './context'

class Grandson extends React.Component {
    
    
  //  孙组件: 同样需引入context,在组件内部添加static contextType = MyContext,
  //   此时将能通过this.context直接获取到上层距离最近的Provider传递的值,此时this.context = {
    
    text:good luck},即父组件传递value。
  static contextType = MyContext
  toParent = () => {
    
    
    this.context.toParent('孙组件向祖父组件传数据')
  }
  render() {
    
    
    return (
      <div
        style={
    
    {
    
    
          backgroundColor: '#13ce66',
          padding: '10px',
          width: '200px',
          margin: 'auto',
          marginTop: '20px',
        }}
      >
        <p>孙组件:</p>
        <span style={
    
    {
    
     color: 'blue' }}>{
    
    this.context.text}</span>
        <div>
          <button onClick={
    
    this.toParent}>向上祖父组件</button>
        </div>
      </div>
    )
  }
}

export default Grandson

Insertar descripción de la imagen aquí
Nota: No importa cuán profunda sea la jerarquía, puede usar el contexto para cargar valores hacia arriba o hacia abajo. Los campos en el contexto tomados del componente inferior deben ser consistentes con los campos pasados ​​en el valor. texto y
sitio web oficial de toParent

redux

Estado de intercambio de datos
Sintaxis básica de Redux

evento de publicación-suscripción

Todos los componentes del modelo de publicación-suscripción están disponibles. El método de evento es relativamente flexible: ya sea entre padres e hijos, entre niveles, hermanos o incluso componentes no relacionados, puede utilizar este método para comunicarse .

modelo de publicación-suscripción

La comunicación entre componentes requiere una referencia a una instancia de una clase, que se implementa mediante el patrón singleton.
En el modelo de publicación/suscripción hay editores y suscriptores, que están vinculados entre sí a través de canales. Contiene principalmente tres objetos:
Suscriptor: objeto que se suscribe a uno o más mensajes del canal.
Editor: el editor del mensaje, el objeto que entrega el mensaje al canal.
Canales: cada canal tiene un nombre y los detalles de implementación del canal están ocultos del código de usuario.

Ideas de diseño de API de modelo de suscripción/publicación

on(): Responsable de registrar el monitoreo de eventos (suscripción) y especificar la función de devolución de llamada cuando se activa (publica) el evento; emit(): Responsable
de activar el evento, que se puede transportar con datos cuando se activa pasando parámetros
off() : Responsable de monitorear Eliminación del dispositivo (evento de despido)

Ventajas y desventajas

En este patrón, un objeto de destino (observador) gestiona todos los objetos (observadores) que dependen de él y envía notificaciones de forma proactiva cuando cambia su propio estado.
Contiene principalmente dos objetos: el observado y el observador.
Ventajas:
la comunicación entre componentes
favorece la cooperación. Para ciertas operaciones, otras no necesitan conocer la lógica específica, solo necesitan iniciarla.
Desventajas:
Problemas de acoplamiento: cada observador debe estar vinculado al objeto observado, lo que introduce acoplamiento
Problemas de rendimiento: en la implementación más básica, el objeto observador debe notificar al observador sincrónicamente. Esto puede provocar cuellos de botella en el rendimiento.

Caso

Instalar evento
npm instalar evento -guardar

  1. 新建event.js
    importa {EventEmitter} de 'eventos';
    exportar el nuevo EventEmitter() predeterminado;
  2. Los otros dos componentes están al mismo nivel.
import React from 'react';
import GrandsonEven from './GrandsonEven';
import GrandsonOtherEven from './GrandsonOtherEven';
 
class Children extends React.Component {
    
    
  render(){
    
    
    return (
      <div>
        <GrandsonEven></GrandsonEven>
        <GrandsonOtherEven></GrandsonOtherEven>
      </div>
    )
  }
}
 
export default Children
  1. En el componente GrandsonEven. Importar evento, agregar oyente en la etapa componenteDidMount, el nombre del evento es consistente con emitir en el componente GrandsonOtherEven
import React from 'react'
import event from './event'

class GrandsonEven extends React.Component {
    
    
  constructor(props) {
    
    
    super(props)
    this.state = {
    
    
      msg: '',
    }
  }
  getData = (params) => {
    
    
    this.setState({
    
    
      msg: params,
    })
  }
  componentDidMount() {
    
    
    //监听eventMsg
    event.on('eventMsg', this.getData)
  }

  render() {
    
    
    return (
      <div
        style={
    
    {
    
    
          backgroundColor: '#13ce66',
          padding: '10px',
          width: '200px',
          margin: 'auto',
          marginTop: '20px',
        }}
      >
        <p>组件一</p>

        <div>组件二通过event传递值过来:{
    
    this.state.msg}</div>
      </div>
    )
  }
}

export default GrandsonEven

Nota: El evento removeListener en componenteWillUnmount ya no es válido
4. En el componente GrandsonOtherEven, importe el evento, el método de enlace del botón y use event.emit para activar (publicar) el evento.

import React from 'react'
import event from './event'

class GrandsonOtherEven extends React.Component {
    
    
  constructor(props) {
    
    
    super(props)
    this.state = {
    
    
      msg: '',
    }
  }
  toOther = () => {
    
    
    //触发test事件的同时,传入希望testHandler感知的参数
    event.emit('eventMsg', '你好')
  }
  render() {
    
    
    return (
      <div
        style={
    
    {
    
    
          backgroundColor: '#13ce66',
          padding: '10px',
          width: '200px',
          margin: 'auto',
          marginTop: '20px',
        }}
      >
        <p>组件二</p>
        <div>
          <button onClick={
    
    this.toOther}>event传值</button>
        </div>
      </div>
    )
  }
}

export default GrandsonOtherEven

Nota: Si dos componentes usan eventos para comunicarse, asegúrese de que los nombres de los eventos de publicación y suscripción sean consistentes, como eventMsg en el ejemplo anterior.

Supongo que te gusta

Origin blog.csdn.net/gao_xu_520/article/details/125311796
Recomendado
Clasificación