はじめに
HTML+JavaScript でアプリを作るのに、Vue.js を愛用してきました。
最近は React.js が流行のようです。使ってみることにしました。
React.js とは
React は、ユーザインタフェース構築のためのJavaScriptライブラリである。シングルページアプリケーションやモバイルアプリケーションの開発におけるベースとして使用することができる。
React.js を使ってみた
・React.js 18
インストールする
React.js のアプリを作るには、Node.js を使ってローカルな開発環境を構築するのが一般的なようです。
今回はあくまでも HTML ファイル一つで、ブラウザだけで動く React.js アプリを作ってみたいと思います。
npmを使わずにReactの開発環境を構築する方法(オフィシャルサイトからダウンロード) | Syntax Error.
npmを使わずにReactの開発環境を構築する方法(CDNで配信されているReactとbabel-coreを利用) | Syntax Error.
HTML ファイルに以下を追記します。
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
React.js を使うコードは、以下の <script>
タグに記載します。
<script type="text/babel">
レンダリングする
HTML ファイルにはアプリの起点になるタグを用意します。
<body>
<div id="root"></div>
</body>
起点になるタグに対して JavaScript のコードで HTML タグをレンダリングします。
const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(
<p>Hello, React.js!</p>
);
参考 React入門チュートリアル (2) JSX | Hypertext Candy
ネットの入門記事を見ていると以下の書き方を多く見かけました。最新の React.js では前述の書き方がいいようです。
const root document.querySelector('#root');
ReactDOM.render((
........
), root);
参考 React 18ではReactDOM.renderではなくcreateRootを使う | iwb.jp
render()
に記述する HTML タグでは、JavaScript のコードの変数や式を埋込できます。
const name = "React.js!";
const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(
<p>Hello, { name }</p>
);
配列のデータを一覧表示することも可能です。
const members = [
{ name: "John", instrument: "guitar" },
{ name: "Paul", instrument: "bass" },
{ name: "George", instrument: "guitar" },
{ name: "Ringo", instrument: "drums" }
];
const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(
<div>
{
members.map((member, index) =>
<p key={ index }> { member.name } plays { member.instrument }.</p>
)
}
</div>
);
個人的には Vue.js の <v-for>
の方が分かりやすく思いますね。
コンポーネントを作成する
React.js は、独自のコンポーネントを作って利用することができます。
class Element extends React.Component {
render() {
return <p>Hello, { this.props.name }</p>;
}
}
const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(
<Element name="React.js" />
);
独自タグを作れると言ってよさそうです。↑
呼出元から値を渡してコンポーネントで受取して使用できます。「属性」と言うそうです。
最近の React.js では、クラスを使うのでなく関数で定義するのがいいそうです。↓
「属性」は引数で受取ります。
const Element = function(props) {
return <p>Hello, { props.name }</p>;
};
const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(
<Element name="React.js" />
);
「属性」を受取するところを書換えます。↓
const Element = function({ name }) {
return <p>Hello, { name }</p>;
};
参考 【React】コンポーネントの基本と使い方を初心者向けに解説! | ちょいっぽ
コンポーネントに状態を加える
コンポーネントは、呼出元から値を受取って使うだけでなく、内部で値を保持して使用します。
カウントアップするボタンのコンポーネントを作ってみます。↓
const CountButton = function() {
let count = 0;
function addCount() {
count += 1;
};
return (
<button onClick={ addCount }>Count: { count }</button>
);
};
const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(
<CountButton />
);
count
の値は変わるのですが、{ count }
で表示される値は変わりません。再描画されないのです。
そこで React.js は、値を変えると同時に再描画させる仕組を用意しています。「状態」を管理すると言います。
const CountButton = function() {
const [ count, setCount ] = React.useState(0);
function addCount() {
setCount(count + 1);
};
以下略
useState
で変数と、変数を更新するメソッドを用意しておきます。useState
の引数は、変数の初期値です。
参考 React入門チュートリアル (3) 属性と状態 | Hypertext Candy
用意する変数が配列のときは、どうでしょう。↓
const Element = function() {
const [ items, setItems ] = React.useState([
{ id: 1, name: "Item1", amount: 1 },
{ id: 2, name: "Item2", amount: 1 },
{ id: 3, name: "Item3", amount: 1 },
]);
function addItem(item) {
items.push(item)
}
function updateItem(index, item) {
items[index] = { ...item };
}
function removeItem(index) {
items.splice(index, 1);
}
以下略
以前にあるように、これでは再描画されません。
useState
で用意したメソッドを使います。↓
function addItem(item) {
setItems([ ...items, item ]);
}
function updateItem(index, item) {
setItems(items.map((item, n) => {
if (n == index) items[index] = { ...item }; return item;
}));
}
function removeItem(index) {
setItems(items.filter((item, n) => (n != index)));
}
参考 useStateで配列要素を追加・削除・変更する方法 - Qiita
イベントをハンドリングする
前述のコードで既に書いていますが、HTML のタグが受取ったイベントを処理することができます。
const Element = function() {
const [ name, setName ] = React.useState("React.js");
function handleChange(e) {
setName(e.target.value);
}
return (
<div>
<p>Hello, { name }</p>
<input value={ name } onChange={ handleChange } />
</div>
);
};
参考 React入門チュートリアル (4) フォームとイベントハンドリング | Hypertext Candy
コンポーネント間で状態を共有する
ルートのコンポーネントで用意した変数を、子供や孫のコンポーネントで使用したいときは、どうしたらいいでしょうか。
useState
で用意した変数とメソッドを、「属性」としてコンポーネントに渡せばいいようです。↓
const App = function() {
const [ count, setCount ] = React.useState(0);
return (
<div>
<Parent count={ count } setCount={ setCount } />
</div>
);
};
const Parent = function({ count, setCount }) {
function addCount() {
setCount(count + 1);
}
return (
<div>
<p>Parent</p>
<button onClick={ addCount }>{ count }</button>
<Child count={ count } setCount={ setCount } />
</div>
);
};
const Child = function({ count, setCount }) {
function addCount() {
setCount(count + 1);
}
return (
<div>
<p>Child</p>
<button onClick={ addCount }>{ count }</button>
<GrandChild count={ count } setCount={ setCount } />
</div>
);
};
const GrandChild = function({ count, setCount }) {
function addCount() {
setCount(count + 1);
}
return (
<div>
<p>GrandChild</p>
<button onClick={ addCount }>{ count }</button>
</div>
);
};
渡したい変数やメソッドが多くなったり、親子の階層が深くなると、引数で渡すのは面倒です。
そこで React.js は、グローバルな「状態」を保持できる仕組を用意しています。
const CountContext = React.createContext();
const App = function() {
const [ count, setCount ] = React.useState(0);
return (
<div>
<CountContext.Provider value={{ count, setCount }}>
<Parent />
</CountContext.Provider>
</div>
);
};
const Parent = function() {
const { count, setCount } = React.useContext(CountContext);
中略
<Child />
</div>
);
};
const Child = function() {
const { count, setCount } = React.useContext(CountContext);
中略
<GrandChild />
</div>
);
};
const GrandChild = function() {
const { count, setCount } = React.useContext(CountContext);
中略
};
useContext
で用意したオブジェクトを使います。
参考 【React】useContextの使い方!初心者向けに分かりやすく解説! | ちょいっぽ
レンダリングのタイミングで実行する
レンダリングのタイミングで処理を実行したいことがあります。
const App = function() {
const [ visible, setVisible ] = React.useState(false);
function toggleVisible() {
setVisible(!visible);
}
return (
<div>
<button onClick={ toggleVisible }>表示を切替</button>
<p>{ visible ? "true" : "false" }</p>
<p>{ visible && <Child /> }</p>
</div>
);
};
const Child = function() {
React.useEffect(function(){
console.log("Hello, Child.");
return(function(){
console.log("Bye, Child.");
});
});
return (
<span>Child</span>
)
};
参考 【React】useEffectの使い方!初心者向けに分かりやすく解説! | ちょいっぽ
userState
の使い所って何なのでしょう。
参考 【保存版】「そのuseEffectの使い方あってる?」と言われる前に
チュートリアル
ここまで基本が分かると、以下のチュートリアルは容易に理解できると思います。