オープニング
現在、Reactはフロントエンド開発において最も人気のあるフレームワークの一つであり、フロントエンドにとって重要であることは自明です。今日からは数ページを使って簡単なReactフレームワークを実装し、Reactの基本的な仕組みを一緒に理解していきましょう。
React
Reactを使ったことがある子はReactのJSX構文を知っているはずですが、実はJSXはHTMLタグと同じような書き方で、パースした後、React.createElementの実際の実装は以下のようになります。
// jsx
function render() {
return <div>hello react</div>;
}
// 解析後、実際に実行されるのは
function render() {
return React.createElement((type: 'div'), {}, 'hello react'); // jsオブジェクトを返す:{type: 'div',attrs: {},children: ['hello react']}
}
そこで、最初の関数であるReact.createElementのモデリングを始めます:
// Reactオブジェクトを作成し、後でそれをエクスポートする。
const React = {};
/*
* createElement
* 3パラメータtype、attrs、childrenなどはすべて同じである。
*
*/
React.createElement = function (type, attrs, ...children) {
return {
type,
attrs,
children,
};
};
export default React;
ReactDOM
上記はReact.createElementの基本的なコアコードですが、次に別のオブジェクト--- ReactDOMを実装します:
// 後でエクスポートされるReactDOMオブジェクトを作成する。
const ReactDOM = {};
/*
* render
* 2次のパラメータ:vnodeはcreateElementによって返されるオブジェクトであり、コンテナはdomノードである、例えば、ドキュメント.getELementById('app')
*
*/
ReactDOM.render = function (vnode, container) {};
export default ReactDOM;
renderメソッドを定義し、具体的にはvnodeとcontainerというパラメータを分析し、vnodeはReact.createElementで返されるオブジェクト、containerはdomノードで、ReactDOM.renderメソッドを修正します:
// 後でエクスポートされるReactDOMオブジェクトを作成する。
const ReactDOM = {};
/*
* render
* 2次のパラメータ:vnodeはcreateElementによって返されるオブジェクトであり、コンテナはdomノードである、例えば、ドキュメント.getELementById('app')
*
*/
ReactDOM.render = function (vnode, container) {
let element;
// 入力されたvnodeが文字列であるかどうかを判断し、文字列である場合は、直接テキストノードを作成する。
if (typeof vnode === 'string') {
element = document.createTextNode(vnode);
} else {
// vnodeオブジェクトであれば、直接htmlノードを作成する。
element = document.createElement(vnode.type);
}
// htmlにノード要素を挿入する
container.appendChild(element);
};
export default ReactDOM;
この時点で、基本的なReactライブラリを実装することができます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="root"></div>
</body>
<!-- react.js ReactとReactDOMの両方のオブジェクトが含まれている。>
<script src="./react.js"></script>
<!-- index.js Reactのメソッドを導入し、実行する>
<script src="./index.js"></script>
</html>
index.jsファイルを見てみましょう。
// JSXが解析され、React.createElement,vnodeオブジェクトを返す
const element = <div>a single react</div>;
// element実際に実行されるのは
// const element = React.createElement(type: 'div', {}, ['a single react'])
ReactDOM.render(element, document.getElementById('root'));
このhtmlファイルをブラウザで実行すると、a single reactという文字が表示されますが、これはReactが正常に実行されていることを意味します。次にindex.jsを変更します:
// JSXが解析され、React.createElement,vnodeオブジェクトを返す
// スパンの余分な層を入れ子にする
const element = (
<div>
<span>a single react</span>
</div>
);
// element実際に実行されるのは
// const element = React.createElement(type: 'div', {}, [React.createElement(type: 'span',{}, ['a single react'])])
ReactDOM.render(element, document.getElementById('root'));
再帰的
ブラウザを更新すると、コンテンツがないことがわかりますが、これはなぜですか?index.jsを参照してください知っている必要があり、スパンの層よりも元の単一の反応に、そうReactDOM.renderでなければなりませんし、変更し、実行の再帰的な方法に変更すると、この問題を解決することができます:
// 後でエクスポートされるReactDOMオブジェクトを作成する。
const ReactDOM = {};
/*
* render
* 2次のパラメータ:vnodeはcreateElementによって返されるオブジェクトであり、コンテナはdomノードである、例えば、ドキュメント.getELementById('app')
*
*/
ReactDOM.render = function (vnode, container) {
// 出口に渡されたコンテナがない場合は、フォールトトレラント判断のビットを行う
if (!container) {
return;
}
let element;
// 入力されたvnodeが文字列であるかどうかを判断し、文字列である場合は、直接テキストノードを作成する。
if (typeof vnode === 'string') {
element = document.createTextNode(vnode);
} else {
// vnodeオブジェクトであれば、直接htmlノードを作成する。
element = document.createElement(vnode.type);
}
// htmlにノード要素を挿入する
container.appendChild(element);
/*
* 子があるかどうかを判断する
* もしあれば、子を繰り返し、ReactDOMを再帰的に実行する。.render
*
*/
if (vnode.children && vnode.children.length) {
vnode.children.forEach((child) => {
/*
* 各子で渡す
* また、domノードとして現在の要素を渡す
*
*/
ReactDOM.render(child, element);
});
}
};
export default ReactDOM;