#はじめに
前回の記事[[1]]で最小構成のreactのHelloWorldをデプロイした。
言われるがままやっただけで理解できていないので、1つ1つ理解していく。
知識としてはprogateでHTML/CSS/javascript/Reactをやった程度。
正直Reactがどういうシステムなのか分かっていないので、現段階ではどのように動かすか理解できればいい。
なぜそうなるのかはあとで後日考察する。
#プログラム
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<!--ディスプレイに合わせて表示-->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!--アドレスバーの背景色を変更(OS/ブラウザに依存)-->
<meta name="theme-color" content="#000000" />
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
function App() {
return (
<div className="App">
Hello,World
</div>
);
}
export default App;
#解析
コードの参照順としてはindex.html→index.js→App.jsとなっている。indexの部分はどのプログラムにもありそうだが、App.jsは他の名前とかにするんだろうか。最小構成だからこれで済んでいるが、おそらくApp.jsで他の作成したコンポーネントを呼び出してさらにネストしていくのだと思われる。
index.html
headタグはコメントに書いてある通り。
普通のhtmlだが、divタグにid="root"とある。
<div id="root"></div>
これがあとあと必要な処理のよう。
index.js
import React from 'react';
import ReactDOM from 'react-dom';
importはpythonとかでも似たようなことしてますね。
厳密な構文を探したところ、このサイト[[2]]に載ってました。
import {インポートするエクスポートの名前} from "モジュールの名前";
中括弧はexport defaultされたものにはいらないようです[[3]]
エクスポートはおそらくApp.jsの最後にもあったやつ。
これも調べたところ載ってました[[4]]。
とりあえずJavaScript モジュールを作成するために使用する文という認識で良さそうです。
export default モジュールの名前;
何がデフォルトなのかを調べたところ、こちらのサイト[[5]]に載ってました。
このjavascriptファイルのデフォルトとして後ろに続く名前のモジュールをエクスポートしますよという意味のよう。
あくまでモジュールの名前なのでエクスポートの名前はimport側で勝手に変えれるよう。
実施にエクスポート名をApp以外にしても普通に動作しました。
長くなりましたが1文目はreactというモジュールをReactという名前でインポートしますよという意味。
となると別にReactの部分は変えても良さそうだが、慣習的に同じにしてるってことだろう。2文目も同様。
ただ、こういうパッケージはnpmかyarnでプロジェクトディレクトリ内にnodemodules内にダウンロードされています。
特に指定しなかったらnodemodulesからとってくるという認識でいいのかな?
import App from './App';
さっきとほぼ同じですが、なんかパスの指定っぽくなってますね。
[[2]]に全く同じような構文はなくて、ファイルの拡張子まで指定しているやつはあります。
import {App} from './App.js';
これなら構文通りなんですが微妙に違います。
思うにこれはモジュールじゃなくてファイルそのものからインポートしてきています。
App.jsではモジュール名をAppとしてエクスポートしているので
import 自分の好きな名前 from "モジュール名までのパス";
みたいな感じじゃないでしょうか。
App.jsをディレクトリに入れてパスを変更したところちゃんと表示されました。
パスを指定しなければnodemodulesを見に行って、それ以外は相対パス指定してねみたいな感じでしょうか。
また気になったので./App.jsに変えてみたところ動作しました。
これはファイルそのものを参照しても大丈夫ということなのか、ただ拡張子省略できますよのどっちの意味なんだろう。
これ以上突っ込むと沼にはまりそうなので拡張子は省略して書けますということにしておきましょう。
ReactDOM.render();
これが全く分かりません。
なんか出力してるんだろうなーぐらいの認識です。
公式リファレンス[[6]]によるオプションを省いた構文を載せます。
ReactDOM.render(element, container)
リファレンスでは渡されたcontainerのDOMにReact要素をレンダーするという風に書いてあります。
まずレンダリングの言葉の定義を考えます。
[[7]]の内容の一部を下記に要約引用します。
レンダリングとは変更前と変更後の仮想DOMの差分を比較し、差分を検知することで仮想DOMを再構築すること。
DOMには変更が直接反映されるリアルDOM(たぶん仮称)と仮想DOMが存在する。
Reactでは2つの仮想DOMがあり、その差分をリアルDOMに反映させる。
要するにこの関数を用いて差分を実際のDOMに反映させているということでしょう。
よくよく考えてみれば結局HTML/CSS/javascriptなんだからそのファイルをいじることが出力の変更になる。
ずっとCでprintfしたりC++でcoutしてたので盲点だった。
つまりこの関数は実際のDOMを変更するための関数という認識でいいでしょう。
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
とするとこのReact.StrictModeで囲まれているのがReact要素(component)、document.getElementById('root')がcontainerだ。
[[8]]によると問題のある書き方を特定するためのモードのよう。
gcc -Wallみたいな感じだろうか。
とりあえずこれはこういうものだと思ってとりあえずつけておけば良さそう。
そうなるとが残るのでこれがReact要素ということでしょう。
この関数は構文上複数のコンポーネントを持てない。
だからApp.jsのようなコンポーネントを集約するためのコンポーネントを作成してこの関数にまとめて渡すのでしょう。
次はdocument.getElementById('root')です。
まずはこの関数の構文が知りたいので調べたところ、こちらに[[9]]載っていました
var element = document.getElementById(id);
idを引数としてElementオブジェクトを返すようです。
Element オブジェクトは調べましたがよく分かりません。
要するにこのidで特定された場所を返すような関数なんでしょう。
今気づきましたがCの癖で関数と呼んでますがメソッドですね。
正直かなり違いますが直すのめんどくさいので次から直すので許してください。
となるとcomponentは各コンポーネントの内容、containerはそれをどこに挿入するかを表してるみたいな感じでしょうか。
たぶん正確には違うと思いますが、構成を理解してプログラムが書ければいいのでこういう理解でいいでしょう。
そうなるとindex.htmlとindex.jsはほとんどいじらなくて良さそうですね。
こういうこと誰も書いてないですが、みんな理解せずになんとなくで書けるんでしょうか?
おまじないにしても最低限理解できないとフォルダ構成とかも変えられない気がするんですが。
しかし、こうやって見てみると見事なまでにカプセル化されてますね。
1つのファイルが1つの機能を持つようにという意思も感じられます。
なんでこんなにファイルを分けるんだと思ってましたが、こういったポリシーがあったのでしょうね。
App.js
export default App;
これは先ほど説明した通りデフォルトでAppというモジュール名でエクスポートするという文です。
Reactの方針として1つのファイルには1つの機能が理想でしょうから、基本的にはデフォルトでいい気がしますね。
function App() {
return (
<div className="App">
Hello,World
</div>
);
}
関数Appを定義しています。
返り値としてDOMを返しているということでしょう。
progateでは
class App extends React.Component {
}
となっていたのですが、関数でもいいんでしょうか。
まあそこは実際に作る際に考えます。
#おわりに
今回はrecctのHelloworldはどのように作られているのか解析しました。
やっとスタートラインに立てた気がします。
Reactではjavascriptよりも強くオブジェクト指向が意識されていますね。
それではまた。
#参考文献
[1]:https://qiita.com/it_tsumugi/items/2acf8c88dbccef413f71
[[1]]:GitHub Pages で最小構成のreactのhelloworldをデプロイしてみた
[2]:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import
[[2]]:import
[3]:https://qiita.com/ryosuketter/items/9588493b633069e06777
[[3]]:ES2015 (ES6) の import や export (default)(React基礎講座4)
[4]:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/export
[[4]]:export
[5]:https://qiita.com/rena_m/items/b9e79dc88e5c5bc5b245
[[5]]:export defaultってなんだろう
[6]:https://ja.reactjs.org/docs/react-dom.html
[[6]]:ReactDOM
[7]:https://zenn.dev/reo777/articles/ad1ae74a2a0d527420d4
[[7]]:Reactのレンダリングと描画の違いを整理する
[8]:https://qiita.com/jkr_2255/items/b154f502d714a3b32e86
[[8]]:React.StrictModeがあぶり出す意外な問題点
[9]:https://developer.mozilla.org/ja/docs/Web/API/Document/getElementById
[[9]]:Document.getElementById()