Maison > interface Web > js tutoriel > le corps du texte

Analyse des composants React et des state|props

不言
Libérer: 2018-07-13 15:10:24
original
1466 Les gens l'ont consulté

L'un des problèmes de la lecture du code source est que vous tomberez dans le dilemme de ne pas redresser la structure principale. Cette série d'articles va redresser le contenu de la structure principale du framework React (JSX/DOM virtuel/composants/. .. )

Les composants sont des fonctions

Dans l'article précédent JSX et Virtual DOM, le processus de rendu de JSX vers l'interface a été expliqué et le code correspondant a été implémenté. L'appel de code est le suivant. :

import React from 'react'
import ReactDOM from 'react-dom'

const element = (
  <p>
    hello<span>world!</span>
  </p>
)

ReactDOM.render(
  element,
  document.getElementById('root')
)
Copier après la connexion

Dans cette section, nous continuerons à explorer le processus de rendu des composants vers l'interface. Nous introduisons ici le concept de composants, 组件本质上就是一个函数, ce qui suit est un code de composant standard :

import React from 'react'

// 写法 1:
class A {
  render() {
    return <p>I'm componentA</p>
  }
}

// 写法 2:无状态组件
const A = () => <p>I'm componentA</p>

ReactDOM.render(<a></a>, document.body)
Copier après la connexion

<a name="componentA"></a> est écrit en JSX, le même que l'article précédent, Babel le convertit en React. Sous la forme de createElement(), le résultat de la conversion est le suivant :

React.createElement(A, null)
Copier après la connexion

Vous pouvez voir que lorsque le JSX est un composant personnalisé, le premier paramètre après createElement devient une fonction, qui est imprimée en repl <a name="componentA"></a>, le résultat est le suivant :

{
  attributes: undefined,
  children: [],
  key: undefined,
  nodeName: ƒ A()
}
Copier après la connexion

Notez que le nodeName dans le DOM virtuel renvoyé est également devenu une fonction. Sur la base de ces indices, nous transformons la fonction render précédente.

function render(vdom, container) {
  if (_.isFunction(vdom.nodeName)) { // 如果 JSX 中是自定义组件
    let component, returnVdom
    if (vdom.nodeName.prototype.render) {
      component = new vdom.nodeName()
      returnVdom = component.render()
    } else {
      returnVdom = vdom.nodeName() // 针对无状态组件:const A = () => <p>I'm componentsA</p>
    }
    render(returnVdom, container)
    return
  }
}
Copier après la connexion

À ce stade, nous avons terminé la logique de traitement du composant.

Implémentation des accessoires et de l'état

Dans le composant A de la section précédente, aucune propriété ni état n'a été introduit. Nous espérons que les propriétés (accessoires) pourront être transférées entre les composants et les fonctions internes de. les composants peuvent être Enregistrer l'état (état).

import React, { Component } from 'react'

class A extends Component {
  render() {
    return <p>I'm {this.props.name}</p>
  }
}

ReactDOM.render(<a></a>, document.body)
Copier après la connexion

Dans le code ci-dessus, vous voyez que la fonction A hérite du composant. Construisons ce composant de classe parent et ajoutons-y state, props, setState et d'autres méthodes d'attribut, afin que les sous-classes puissent en hériter.

function Component(props) {
  this.props = props
  this.state = this.state || {}
}
Copier après la connexion

Tout d'abord, nous passons les accessoires de l'extérieur du composant dans le composant et modifions le code suivant dans la fonction de rendu :

function render(vdom, container) {
  if (_.isFunction(vdom.nodeName)) {
    let component, returnVdom
    if (vdom.nodeName.prototype.render) {
      component = new vdom.nodeName(vdom.attributes) // 将组件外的 props 传进组件内
      returnVdom = component.render()
    } else {
      returnVdom = vdom.nodeName(vdom.attributes)     // 处理无状态组件:const A = (props) => <p>I'm {props.name}</p>
    }
    ...
  }
  ...
}
Copier après la connexion

Après avoir terminé le transfert des accessoires entre les composants, Parlons-en. L'état, en réaction, change l'état du composant via setState. Les chapitres suivants approfondiront cette API (asynchrone). Voici une implémentation simple comme suit :

function Component(props) {
  this.props = props
  this.state = this.state || {}
}

Component.prototype.setState = function() {
  this.state = Object.assign({}, this.state, updateObj) // 这里简单实现,后续篇章会深入探究
  const returnVdom = this.render() // 重新渲染
  document.getElementById('root').innerHTML = null
  render(returnVdom, document.getElementById('root'))
}
Copier après la connexion

Bien que setState ait été implémenté à ce stade. time, mais ce n'est évidemment pas ce que l'on veut écrire le nœud document.getElementById('root') dans setState. On transfère le nœud dom lié à la fonction _render :

Component.prototype.setState = function(updateObj) {
  this.state = Object.assign({}, this.state, updateObj)
  _render(this) // 重新渲染
}
Copier après la connexion

Naturellement, reconstruisons la fonction render qui lui est associée. :

function render(vdom, container) {
  let component
  if (_.isFunction(vdom.nodeName)) {
    if (vdom.nodeName.prototype.render) {
      component = new vdom.nodeName(vdom.attributes)
    } else {
      component = vdom.nodeName(vdom.attributes) // 处理无状态组件:const A = (props) => <p>I'm {props.name}</p>
    }
  }
  component ? _render(component, container) : _render(vdom, container)
}
Copier après la connexion

Le but de séparer la fonction _render de la fonction render est de permettre à la logique _render d'être appelée dans la fonction setState. La fonction _render complète est la suivante :

function _render(component, container) {
  const vdom = component.render ? component.render() : component
  if (_.isString(vdom) || _.isNumber(vdom)) {
    container.innerText = container.innerText + vdom
    return
  }
  const dom = document.createElement(vdom.nodeName)
  for (let attr in vdom.attributes) {
    setAttribute(dom, attr, vdom.attributes[attr])
  }
  vdom.children.forEach(vdomChild => render(vdomChild, dom))
  if (component.container) {  // 注意:调用 setState 方法时是进入这段逻辑,从而实现我们将 dom 的逻辑与 setState 函数分离的目标;知识点: new 出来的同一个实例
    component.container.innerHTML = null
    component.container.appendChild(dom)
    return
  }
  component.container = container
  container.appendChild(dom)
}
Copier après la connexion

Utilisons le cas d'utilisation suivant pour exécuter la réaction écrite !

class A extends Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 1
    }
  }

  click() {
    this.setState({
      count: ++this.state.count
    })
  }

  render() {
    return (
      <p>
        <button>Click Me!</button>
        </p><p>{this.props.name}:{this.state.count}</p>
      
    )
  }
}

ReactDOM.render(
  <a></a>,
  document.getElementById('root')
)
Copier après la connexion

Le rendu est le suivant :

Analyse des composants React et des state|props

À ce stade, nous avons implémenté la logique des accessoires et des parties d'état.

Résumé

Les composants sont des fonctions ; lorsque JSX est un composant personnalisé, le premier paramètre dans React.createElement(fn, ..) après la conversion Babel devient une fonction, sauf que l'autre logique est la comme lorsqu'il s'agit d'un élément html dans JSX ;

De plus, nous avons encapsulé des API telles que state/props/setState dans la classe parent React.Component, afin qu'elles puissent être appelées dans les sous-classes de ces propriétés et méthodes.

Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'étude de chacun. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois !

Recommandations associées :

Explication détaillée de la configuration de config/index.js dans vue

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal