このチュートリアルはこのチュートリアルに基づいていますが、JSX、typescript、および実装がより簡単なアプローチを使用しています。私の GitHub リポジトリでメモとコードをチェックアウトできます。
次に、反応性について話しましょう。
古いファイバーを保存する
新しいファイバーと比較できるように、古いファイバーを保存する必要があります。これを行うには、ファイバーにフィールドを追加します。また、コミットされたフィールドも必要です。これは後で役立ちます。
export interface Fiber { type: string props: VDomAttributes parent: Fiber | null child: Fiber | null sibling: Fiber | null dom: HTMLElement | Text | null alternate: Fiber | null committed: boolean }
次に、ここでコミットされた状態を設定します。
function commit() { function commitChildren(fiber: Fiber | null) { if(!fiber) { return } if(fiber.dom && fiber.parent?.dom) { fiber.parent.dom.appendChild(fiber.dom) fiber.committed = true } if(fiber.dom && fiber.parent && isFragment(fiber.parent.vDom) && !fiber.committed) { let parent = fiber.parent // find the first parent that is not a fragment while(parent && isFragment(parent.vDom)) { // the root element is guaranteed to not be a fragment has has a non-fragment parent parent = parent.parent! } parent.dom?.appendChild(fiber.dom!) fiber.committed = true } commitChildren(fiber.child) commitChildren(fiber.sibling) } commitChildren(wip) wipParent?.appendChild(wip!.dom!) wip!.committed = true wip = null }
古いファイバーツリーも保存する必要があります。
let oldFiber: Fiber | null = null function commit() { function commitChildren(fiber: Fiber | null) { if(!fiber) { return } if(fiber.dom && fiber.parent?.dom) { fiber.parent.dom.appendChild(fiber.dom) fiber.committed = true } commitChildren(fiber.child) commitChildren(fiber.sibling) } commitChildren(wip) wipParent?.appendChild(wip!.dom!) wip!.committed = true oldFiber = wip wip = null }
ここで、反復中に古いファイバーと新しいファイバーを比較する必要があります。これは調整プロセスと呼ばれます。
和解
古いファイバーと新しいファイバーを比較する必要があります。最初の作業では、まず古いファイバーを入れます。
export function render(vDom: VDomNode, parent: HTMLElement) { wip = { parent: null, sibling: null, child: null, vDom: vDom, dom: null, committed: false, alternate: oldFiber, } wipParent = parent nextUnitOfWork = wip }
次に、新しいファイバーの作成を新しい関数に分離します。
function reconcile(fiber: Fiber, isFragment: boolean) { if (isElement(fiber.vDom)) { const elements = fiber.vDom.children ?? [] let index = 0 let prevSibling = null while (index <p>ただし、古いファイバーを新しいファイバーに取り付ける必要があります。<br> </p> <pre class="brush:php;toolbar:false">function reconcile(fiber: Fiber, isFragment: boolean) { if (isElement(fiber.vDom)) { const elements = fiber.vDom.children ?? [] let index = 0 let prevSibling = null let currentOldFiber = fiber.alternate?.child ?? null while (index <p>これで、古いファイバーが新しいファイバーに取り付けられました。しかし、再レンダリングをトリガーするものは何もありません。今のところ、ボタンを追加して手動で再レンダリングをトリガーします。まだ状態を持っていないため、vDOM を変更するために props を使用します。<br> </p> <pre class="brush:php;toolbar:false">import { render } from "./runtime"; import { createElement, fragment, VDomAttributes, VDomNode } from "./v-dom"; type FuncComponent = (props: VDomAttributes, children: VDomNode[]) => JSX.Element const App: FuncComponent = (props: VDomAttributes, __: VDomNode[]) => { return <div> <h1 id="H">H1</h1> <h2 id="props-example-toString">{props["example"]?.toString()}</h2> { props["show"] ? <p>show</p> : > } <h1 id="H">H1</h1> > </div> } const app = document.getElementById('app') const renderButton = document.createElement('button') renderButton.textContent = 'Render' let cnt = 0 renderButton.addEventListener('click', () => { const vDom: VDomNode = App({ "example": (new Date()).toString(), "show": cnt % 2 === 0 }, []) as unknown as VDomNode cnt++ render(vDom, app!) }) document.body.appendChild(renderButton)
ここで、renderButton をクリックすると、レンダリングされた結果が 1 回繰り返されます。これは、現在のロジックはすべて、レンダリングされた vDOM をドキュメントに配置するだけであるためです。
コミット関数に console.log を追加すると、代替ファイバーが出力されることがわかります。
次に、古いファイバーと新しいファイバーを処理する方法を定義し、その情報に基づいて DOM を変更する必要があります。ルールは以下の通りです。
新しいファイバーごとに、
- 古いファイバーがあった場合は、古いファイバーの内容と新しいファイバーを比較し、異なる場合は、古い DOM ノードを新しい DOM ノードに置き換えます。そうでない場合は、古い DOM ノードをコピーします。新しい DOM ノード。 2 つの vDOM が等しいということは、それらのタグとすべてのプロパティが等しいことを意味することに注意してください。彼らの子供たちは異なる可能性があります。
- 古いファイバーがない場合は、新しい DOM ノードを作成し、親に追加します。
- 新しいファイバーに子や兄弟がないが、古いファイバーに子や兄弟がある場合は、古い子や兄弟を再帰的に削除します。
ちょっと混乱してる?そうですね、コードだけお見せします。まず古い DOM 作成を削除します。次に、上記のルールを適用します。
最初のルールは、古い繊維がある場合、古い繊維の含有量を新しい繊維と比較します。異なる場合は、古い DOM ノードを新しい DOM ノードに置き換えるか、古い DOM ノードを新しい DOM ノードにコピーします。
export function vDOMEquals(a: VDomNode, b: VDomNode): boolean { if (isString(a) && isString(b)) { return a === b } else if (isElement(a) && isElement(b)) { let ret = a.tag === b.tag && a.key === b.key if (!ret) return false if (a.props && b.props) { const aProps = a.props const bProps = b.props const aKeys = Object.keys(aProps) const bKeys = Object.keys(bProps) if (aKeys.length !== bKeys.length) return false for (let i = 0; i <p>その後、いくつかの小さなリファクタリングを作成しました。<br> </p><pre class="brush:php;toolbar:false">export interface Fiber { type: string props: VDomAttributes parent: Fiber | null child: Fiber | null sibling: Fiber | null dom: HTMLElement | Text | null alternate: Fiber | null committed: boolean }
コミットに関しては、古いファイバーと新しいファイバーを比較するための追加の代替フィールドが用意されています。
これはオリジナルのコミット関数です。
function commit() { function commitChildren(fiber: Fiber | null) { if(!fiber) { return } if(fiber.dom && fiber.parent?.dom) { fiber.parent.dom.appendChild(fiber.dom) fiber.committed = true } if(fiber.dom && fiber.parent && isFragment(fiber.parent.vDom) && !fiber.committed) { let parent = fiber.parent // find the first parent that is not a fragment while(parent && isFragment(parent.vDom)) { // the root element is guaranteed to not be a fragment has has a non-fragment parent parent = parent.parent! } parent.dom?.appendChild(fiber.dom!) fiber.committed = true } commitChildren(fiber.child) commitChildren(fiber.sibling) } commitChildren(wip) wipParent?.appendChild(wip!.dom!) wip!.committed = true wip = null }
名前を少し変更します。古い名前は間違っています (ごめんなさい)。
let oldFiber: Fiber | null = null function commit() { function commitChildren(fiber: Fiber | null) { if(!fiber) { return } if(fiber.dom && fiber.parent?.dom) { fiber.parent.dom.appendChild(fiber.dom) fiber.committed = true } commitChildren(fiber.child) commitChildren(fiber.sibling) } commitChildren(wip) wipParent?.appendChild(wip!.dom!) wip!.committed = true oldFiber = wip wip = null }
追加、コピー、置換
それではどうすればいいでしょうか?古いロジックは追加するだけなので、それを抽出します。
export function render(vDom: VDomNode, parent: HTMLElement) { wip = { parent: null, sibling: null, child: null, vDom: vDom, dom: null, committed: false, alternate: oldFiber, } wipParent = parent nextUnitOfWork = wip }
柔軟性を高めるために、DOM の構築をコミットフェーズまで遅らせる必要があります。
function reconcile(fiber: Fiber, isFragment: boolean) { if (isElement(fiber.vDom)) { const elements = fiber.vDom.children ?? [] let index = 0 let prevSibling = null while (index <p>最初と 2 番目のルールに従って、それらを次のコードにリファクタリングします。<br> </p> <pre class="brush:php;toolbar:false">function reconcile(fiber: Fiber, isFragment: boolean) { if (isElement(fiber.vDom)) { const elements = fiber.vDom.children ?? [] let index = 0 let prevSibling = null let currentOldFiber = fiber.alternate?.child ?? null while (index <p>JavaScript ではすべての値が参照であることに常に留意してください。 Fiber.dom = Fiber.alternate.dom の場合、 Fiber.dom と Fiber.alternate.dom は同じオブジェクトを指します。 Fiber.dom を変更すると、fiber.alternate.dom も変更され、その逆も同様です。そのため、置き換える際には、単に Fiber.alternate.dom?.replaceWith(fiber.dom) を使用しました。これにより、古い DOM が新しい DOM に置き換えられます。以前の親がコピーされると、その DOM の Fiber.alternate.dom が保持されますが、その DOM も置き換えられます。</p> <p>ただし、削除はまだ対応していませんでした。</p> <h3> いくつかの事故 </h3> <p>わかりました。前のコードには、より複雑な JSX を作成しているときに見つけたいくつかのバグが含まれています。そのため、削除を実装する前に、それらを修正しましょう。</p> <p>以前はバグがありました - プロパティにリストを渡すことができません。この機会にそれを修正しましょう。<br> </p> <pre class="brush:php;toolbar:false">import { render } from "./runtime"; import { createElement, fragment, VDomAttributes, VDomNode } from "./v-dom"; type FuncComponent = (props: VDomAttributes, children: VDomNode[]) => JSX.Element const App: FuncComponent = (props: VDomAttributes, __: VDomNode[]) => { return <div> <h1 id="H">H1</h1> <h2 id="props-example-toString">{props["example"]?.toString()}</h2> { props["show"] ? <p>show</p> : > } <h1 id="H">H1</h1> > </div> } const app = document.getElementById('app') const renderButton = document.createElement('button') renderButton.textContent = 'Render' let cnt = 0 renderButton.addEventListener('click', () => { const vDom: VDomNode = App({ "example": (new Date()).toString(), "show": cnt % 2 === 0 }, []) as unknown as VDomNode cnt++ render(vDom, app!) }) document.body.appendChild(renderButton)
それから、タイプのものを修正するだけです。私にとってエラーは 1 つだけなので、ご自身で修正してください。
ただし、次のコードがある場合、
export function vDOMEquals(a: VDomNode, b: VDomNode): boolean { if (isString(a) && isString(b)) { return a === b } else if (isElement(a) && isElement(b)) { let ret = a.tag === b.tag && a.key === b.key if (!ret) return false if (a.props && b.props) { const aProps = a.props const bProps = b.props const aKeys = Object.keys(aProps) const bKeys = Object.keys(bProps) if (aKeys.length !== bKeys.length) return false for (let i = 0; i <p>私たちのものがまた壊れました...</p> <p>わかりました。これは、上記の場合、子が入れ子の配列になる可能性があるため、それらをフラットにする必要があるからです。</p> <p>しかし、それだけでは十分ではありません。createDom は整数ではなく、文字列または要素のいずれかを認識するだけなので、数値を文字列化する必要があります。<br> </p> <pre class="brush:php;toolbar:false">function buildDom(fiber: Fiber, fiberIsFragment: boolean) { if(fiber.dom) return if(fiberIsFragment) return fiber.dom = createDom(fiber.vDom) } function performUnitOfWork(nextUnitOfWork: Fiber | null): Fiber | null { if(!nextUnitOfWork) { return null } const fiber = nextUnitOfWork const fiberIsFragment = isFragment(fiber.vDom) reconcile(fiber) buildDom(fiber, fiberIsFragment); if (fiber.child) { return fiber.child } let nextFiber: Fiber | null = fiber while (nextFiber) { if (nextFiber.sibling) { return nextFiber.sibling } nextFiber = nextFiber.parent } return null }
よし、これでうまくいくようになりました。
レンダリング ボタンを押すと、リストは更新されますが、古い要素はまだ残ります。古い要素を削除する必要があります。
取り除く
ここでルールを再説明します。新しいファイバーに子や兄弟がなく、古いファイバーに子や兄弟がある場合、古い子や兄弟を再帰的に削除します。
function commit() { function commitChildren(fiber: Fiber | null) { if(!fiber) { return } if(fiber.dom && fiber.parent?.dom) { fiber.parent?.dom?.appendChild(fiber.dom) fiber.committed = true } if(fiber.dom && fiber.parent && isFragment(fiber.parent.vDom) && !fiber.committed) { let parent = fiber.parent // find the first parent that is not a fragment while(parent && isFragment(parent.vDom)) { // the root element is guaranteed to not be a fragment has has a non-fragment parent parent = parent.parent! } parent.dom?.appendChild(fiber.dom!) fiber.committed = true } commitChildren(fiber.child) commitChildren(fiber.sibling) } commitChildren(wip) wipParent?.appendChild(wip!.dom!) wip!.committed = true oldFiber = wip wip = null }
再帰的な削除を行わないと、削除が必要な要素が複数あるときに古い要素がぶら下がってしまいます。
に変更できます。
function commit() { function commitToParent(fiber: Fiber | null) { if(!fiber) { return } if(fiber.dom && fiber.parent?.dom) { fiber.parent?.dom?.appendChild(fiber.dom) fiber.committed = true } if(fiber.dom && fiber.parent && isFragment(fiber.parent.vDom) && !fiber.committed) { let parent = fiber.parent // find the first parent that is not a fragment while(parent && isFragment(parent.vDom)) { // the root element is guaranteed to not be a fragment has has a non-fragment parent parent = parent.parent! } parent.dom?.appendChild(fiber.dom!) fiber.committed = true } commitToParent(fiber.child) commitToParent(fiber.sibling) } commitToParent(wip) wipParent?.appendChild(wip!.dom!) wip!.committed = true oldFiber = wip wip = null }
ご参考までに。
まとめ
これは難しい章ですが、正直に言うとかなり伝統的なコーディングです。ただし、ここまでで、React が下から上までどのように動作するかを理解しました。
実際には、すでに動作するようになりました。プロパティを変更するたびに手動で再レンダリングをトリガーできます。しかし、そのようなイライラする手作業は私たちが望んでいることではありません。反応性を自動化したいと考えています。したがって、フックについては次の章で説明します。
以上が小さな React Chpdating vDOM を構築するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

開発環境におけるPythonとJavaScriptの両方の選択が重要です。 1)Pythonの開発環境には、Pycharm、Jupyternotebook、Anacondaが含まれます。これらは、データサイエンスと迅速なプロトタイピングに適しています。 2)JavaScriptの開発環境には、フロントエンドおよびバックエンド開発に適したnode.js、vscode、およびwebpackが含まれます。プロジェクトのニーズに応じて適切なツールを選択すると、開発効率とプロジェクトの成功率が向上する可能性があります。

はい、JavaScriptのエンジンコアはCで記述されています。1)C言語は、JavaScriptエンジンの開発に適した効率的なパフォーマンスと基礎となる制御を提供します。 2)V8エンジンを例にとると、そのコアはCで記述され、Cの効率とオブジェクト指向の特性を組み合わせて書かれています。3)JavaScriptエンジンの作業原理には、解析、コンパイル、実行が含まれ、C言語はこれらのプロセスで重要な役割を果たします。

JavaScriptは、Webページのインタラクティブ性とダイナミズムを向上させるため、現代のWebサイトの中心にあります。 1)ページを更新せずにコンテンツを変更できます。2)Domapiを介してWebページを操作する、3)アニメーションやドラッグアンドドロップなどの複雑なインタラクティブ効果、4)ユーザーエクスペリエンスを改善するためのパフォーマンスとベストプラクティスを最適化します。

CおよびJavaScriptは、WebAssemblyを介して相互運用性を実現します。 1)CコードはWebAssemblyモジュールにコンパイルされ、JavaScript環境に導入され、コンピューティングパワーが強化されます。 2)ゲーム開発では、Cは物理エンジンとグラフィックスレンダリングを処理し、JavaScriptはゲームロジックとユーザーインターフェイスを担当します。

JavaScriptは、Webサイト、モバイルアプリケーション、デスクトップアプリケーション、サーバー側のプログラミングで広く使用されています。 1)Webサイト開発では、JavaScriptはHTMLおよびCSSと一緒にDOMを運用して、JQueryやReactなどのフレームワークをサポートします。 2)ReactNativeおよびIonicを通じて、JavaScriptはクロスプラットフォームモバイルアプリケーションを開発するために使用されます。 3)電子フレームワークにより、JavaScriptはデスクトップアプリケーションを構築できます。 4)node.jsを使用すると、JavaScriptがサーバー側で実行され、高い並行リクエストをサポートします。

Pythonはデータサイエンスと自動化により適していますが、JavaScriptはフロントエンドとフルスタックの開発により適しています。 1. Pythonは、データ処理とモデリングのためにNumpyやPandasなどのライブラリを使用して、データサイエンスと機械学習でうまく機能します。 2。Pythonは、自動化とスクリプトにおいて簡潔で効率的です。 3. JavaScriptはフロントエンド開発に不可欠であり、動的なWebページと単一ページアプリケーションの構築に使用されます。 4. JavaScriptは、node.jsを通じてバックエンド開発において役割を果たし、フルスタック開発をサポートします。

CとCは、主に通訳者とJITコンパイラを実装するために使用されるJavaScriptエンジンで重要な役割を果たします。 1)cは、JavaScriptソースコードを解析し、抽象的な構文ツリーを生成するために使用されます。 2)Cは、Bytecodeの生成と実行を担当します。 3)Cは、JITコンパイラを実装し、実行時にホットスポットコードを最適化およびコンパイルし、JavaScriptの実行効率を大幅に改善します。

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。


ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

VSCode Windows 64 ビットのダウンロード
Microsoft によって発売された無料で強力な IDE エディター

AtomエディタMac版ダウンロード
最も人気のあるオープンソースエディター

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境

MinGW - Minimalist GNU for Windows
このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

DVWA
Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、

ホットトピック









