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/. .. )
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.
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 :
À ce stade, nous avons implémenté la logique des accessoires et des parties d'état.
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!