Maison  >  Article  >  interface Web  >  Analyse des composants React et des state|props

Analyse des composants React et des state|props

不言
不言original
2018-07-13 15:10:241467parcourir

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')
)

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)

<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)

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()
}

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
  }
}

À 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)

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 || {}
}

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>
    }
    ...
  }
  ...
}

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'))
}

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) // 重新渲染
}

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)
}

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)
}

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')
)

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!

Déclaration:
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