React コンポーネントと state|props の解析
ソース コードを読む際の難点の 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、その他の属性メソッドを追加して、サブクラスがそれらを継承できるようにしましょう。
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') )
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 サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









呼び出しメソッド: 1. クラス コンポーネントの呼び出しは、React.createRef()、ref または props のカスタム onRef 属性の関数宣言を使用して実装できます; 2. 関数コンポーネントおよびフック コンポーネントの呼び出しは、useImperativeHandle または forwardRef を使用して実装できます。子コンポーネントの ref が実装されています。

React ソースコードをデバッグするにはどうすればよいですか?次の記事では、さまざまなツールで React のソース コードをデバッグする方法について説明し、コントリビューター、create-react-app、vite プロジェクトで React の実際のソース コードをデバッグする方法を紹介します。

React カスタム フックは、コンポーネント ロジックを再利用可能な関数にカプセル化する方法であり、クラスを作成せずに状態ロジックを再利用する方法を提供します。この記事では、カプセル化フックをカスタマイズする方法を詳しく紹介します。

React はなぜ Vite をアプリケーション構築の第一の選択肢として使用しないのでしょうか?次の記事では、React が Vite をデフォルトの推奨事項として推奨しない理由について説明します。

React で div の高さを設定する方法: 1. CSS を通じて div の高さを実装します; 2. ステートでオブジェクト C を宣言し、オブジェクトに変更ボタンのスタイルを格納し、A を取得して C の "marginTop" をリセットします. それがキャンです。

この記事では、日常の開発で頻繁に使用される、優れた実用的な React コンポーネント ライブラリを 7 つ紹介します。

この記事では、よりシンプルな React コードを記述するための 10 の実践的なヒントを紹介します。
![[翻訳] カスタムフックを使用した React コンポーネントのリファクタリング](https://img.php.cn/upload/article/000/000/024/63c690a1b11d0794.jpg?x-oss-process=image/resize,m_fill,h_207,w_330)
React の関数コンポーネントについて人々が話し、関数コンポーネントは必然的に大きくなり、論理的により複雑になるという話をよく聞きます。結局のところ、コンポーネントを「関数」で記述したため、コンポーネントが拡張され、関数も拡張し続けることを受け入れる必要があります。
