React コンポーネントと state|props の解析

不言
リリース: 2018-07-13 15:10:24
オリジナル
1466 人が閲覧しました

ソース コードを読む際の難点の 1 つは、バックボーンを整理しないというジレンマに陥ることです。このシリーズの記事では、React フレームワーク (JSX/仮想 DOM/コンポーネント/...) のバックボーン コンテンツを整理します。 ) (x)react.を実装しながら

コンポーネントは関数です

前の記事 JSX と仮想 DOM では、インターフェースへの JSX レンダリングのプロセスを説明し、対応するコードを実装しました。コード呼び出しは次のとおりです。

このセクションでは、コンポーネントがインターフェイス プロセスにどのようにレンダリングされるかを引き続き調査していきます。ここでは、コンポーネントの概念を紹介します。コンポーネントは本質的に関数です。以下は標準コンポーネント コードです:

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

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

ReactDOM.render(
  element,
  document.getElementById('root')
)
ログイン後にコピー
组件本质上就是一个函数,如下就是一段标准组件代码:
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> 是 JSX 的写法,和上一篇同理,babel 将其转化为 React.createElement() 的形式,转化结果如下所示:

React.createElement(A, null)
ログイン後にコピー

可以看到当 JSX 中是自定义组件的时候,createElement 后接的第一个参数变为了函数,在 repl 打印 <a name="componentA"></a>,结果如下:

{
  attributes: undefined,
  children: [],
  key: undefined,
  nodeName: ƒ A()
}
ログイン後にコピー

注意这时返回的 Virtual DOM 中的 nodeName 也变为了函数。根据这些线索,我们对之前的 render 函数进行改造。

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
  }
}
ログイン後にコピー

至此,我们完成了对组件的处理逻辑。

props 和 state 的实现

在上个小节组件 A 中,是没有引入任何属性和状态的,我们希望组件间能进行属性的传递(props)以及组件内能进行状态的记录(state)。

import React, { Component } from 'react'

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

ReactDOM.render(<a></a>, document.body)
ログイン後にコピー

在上面这段代码中,看到 A 函数继承自 Component。我们来构造这个父类 Component,并在其添加 state、props、setState 等属性方法,从而让子类继承到它们。

function Component(props) {
  this.props = props
  this.state = this.state || {}
}
ログイン後にコピー

首先,我们将组件外的 props 传进组件内,修改 render 函数中以下代码:

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>
    }
    ...
  }
  ...
}
ログイン後にコピー

实现完组件间 props 的传递后,再来聊聊 state,在 react 中是通过 setState 来完成组件状态的改变的,后续章节会对这个 api(异步)深入探究,这里简单实现如下:

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'))
}
ログイン後にコピー

此时虽然已经实现了 setState 的功能,但是 document.getElementById('root')<a name="componentA"></a> > 前回の記事と同様に、babel で React.createElement() の形式に変換すると以下のようになります。 JSX、createElement の後に最初のパラメータが関数になり、repl で <a name="componentA"></a> を出力すると、結果は次のようになります。

Component.prototype.setState = function(updateObj) {
  this.state = Object.assign({}, this.state, updateObj)
  _render(this) // 重新渲染
}
ログイン後にコピー

返された仮想 DOM も機能するように変更されました。これらの手がかりに基づいて、前の render 関数を変換しました。

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)
}
ログイン後にコピー

この時点で、コンポーネントの処理ロジックが完成しました。

プロパティと状態の実装

前のセクションのコンポーネント A では、プロパティと状態が導入されませんでした。コンポーネント (プロパティ) 間でプロパティを転送でき、コンポーネント (状態) 内で状態を記録できることを期待しています。

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)
}
ログイン後にコピー

上記のコードでは、A 関数が Component から継承していることがわかります。この親クラス Component を構築し、それに state、props、setState、その他の属性メソッドを追加して、サブクラスがそれらを継承できるようにしましょう。 React コンポーネントと state|props の解析

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')
)
ログイン後にコピー
まず、コンポーネントの外部からコンポーネントに props を渡し、render 関数で次のコードを変更します。

rrreee

コンポーネント間での props の転送が完了したら、react では setState を使用して状態について説明します。コンポーネントの状態を完了します。変更については、後続の章でこの API (非同期) について詳しく説明します。ここでの簡単な実装は次のとおりです。

rrreee

この時点では setState 関数が実装されていますが、document.getElementById('root' ) setState にノードを書き込むのは明らかにそうではありません。_render 関数に関連する dom ノードを転送します:

rrreee

当然、それに関連する render 関数を再構築します:

rrreee

render 関数 この関数の目的は、setState 関数で _render ロジックを呼び出せるようにすることです。完全な _render 関数は次のとおりです:

rrreee

次のユースケースを使用して、書かれた React を実行してみましょう!

rrreee

レンダリングは次のとおりです:

コンポーネントは関数です。JSX がカスタムコンポーネントの場合、Babel 変換後の React.createElement(fn, ..) の最初のパラメーターは関数になります。また、他のロジックや HTML 要素についても同様です。 JSX; 🎜🎜 さらに、state/props/setState などの API を親クラス React.Component にカプセル化して、これらのプロパティとメソッドをサブクラスで呼び出すことができるようにしました。 🎜🎜上記がこの記事の全内容です。その他の関連コンテンツについては、PHP 中国語 Web サイトをご覧ください。 🎜🎜関連する推奨事項: 🎜🎜🎜 vue の config/index.js の詳細な説明: 構成🎜🎜🎜🎜 Angular テンプレート構文の説明🎜🎜🎜

以上がReact コンポーネントと state|props の解析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート