■create-react-appのインストール&Hello Worldの表示
create-react-appはFacebookが提供しているCLIツールです。
環境構築の手間をスキップして学習に集中できます。
// create-react-appのインストール
yarn global add create-react-app
// Reactアプリケーションの作成
create-react-app hello-world
// hello-worldに移動
cd hello-world
// 開発開始
yarn start
Hello Worldを表示するにはsrc/App.js内をこのように書き換えます。
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code>and save to reload {/* この行を「Hello World」に書き換える */}
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
ちなみにこのreturn()内の部分はぱっと見HTMLに見えますが、実際はJSXというものになっています。
詳細は公式をご確認ください。( https://ja.reactjs.org/docs/introducing-jsx.html )
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
//このreturnの中がJSX
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Hello World
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
■コンポーネントについて
Reactのコンポーネントには「関数コンポーネント」と「クラスコンポーネント」の二種類があります。
<関数コンポーネント>
実は先ほどのHello Worldを表示した時のApp.jsが既に関数コンポーネントの形になっていました。
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Hello World
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
わかりやすく余計な部分を省いた形が下記になります。
※ちなみにですが、JSXが内部的にReactを使用しているため「import React from 'react';」の記述を無くすとエラーになります。
import React from 'react';
function FunctionComponentA() {
return (
<div className="function-component_A">
function-component_Aです。
</div>
);
}
export default FunctionComponentA;
このようにsrc/index.jsに追加することで反映されます。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import FunctionComponentA from './FunctionComponentA' //ここに追加
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<React.StrictMode>
<FunctionComponentA /> {/* ここに追加 */}
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
このようにアロー関数の形で定義することもできます。
import React from 'react';
const FunctionComponentB = () => {
return (
<div className="function-component_B">
function-component_Bです。
</div>
);
}
export default FunctionComponentB;
<クラスコンポーネント>
クラスコンポーネントはこのように定義します。
import React, { Component } from 'react';
class ClassComponent extends Component {
render() {
return (
<div className="class-component">
ClassComponentです。
</div>
)
}
}
export default ClassComponent;
Componentを継承したクラスとして定義します。
<関数コンポーネントとクラスコンポーネントそれぞれの特徴>
関数コンポーネント
・簡潔に書けるので基本はこちらが望ましい。
・状態管理によるレンダー制御ができない。
クラスコンポーネント
・状態管理によるレンダー制御が可能。
・ローカルstateやライフサイクルメソッドが利用可能。
■props
こちらが見本になります。
import React from 'react';
const Parent = () => {
return (
<div>
<strong>表示されるとこうなります。</strong>
<Child name={"ポール・マッカートニー"} instrument={"ベース"} />
<Child name={"ジョン・レノン"} instrument={"ギター"} />
<Child name={"ジョージ・ハリスン"} instrument={"ギター"} />
<Child name={"リンゴ・スター"} instrument={"ドラム"} />
</div>
)
}
const Child = (props) => {
return (
<div>僕は{props.name}です。担当は{props.instrument}です。</div>
)
}
export default Parent;
Child(子コポーネント)をParent(親コンポーネント)で利用する際に属性のような形でpropsを渡すことができます。
渡ったpropsはChild側で受け取り、利用するという流れになります。
データを配列で一括に渡したいと言う時には、「map」を利用することで実現可能です。
下記キャプチャでは、配列ビートルズをmapで展開しています。
import React from 'react';
const Parent2 = () => {
const beatles = [
{
name: "ポール・マッカートニー",
instrument: "ベース"
},
{
name: "ジョン・レノン",
instrument: "ギター"
},
{
name: "ジョージ・ハリスン",
instrument: "ギター"
},
{
name: "リンゴ・スター",
instrument: "ドラム"
}
]
return (
<div>
<strong>表示されるとこうなります。(map)</strong>
{
beatles.map((beatlesMember, index) => {
return <Child name={beatlesMember.name} instrument={beatlesMember.instrument} key={index} />
})
}
</div>
)
}
const Child = (props) => {
return (
<div>僕は{props.name}です。担当は{props.instrument}です。</div>
)
}
export default Parent2;
■prop-types(型チェック)
こちらが見本になります。
import React from 'react';
import PropTypes from 'prop-types' //これをimportします。
const Parent = () => {
return (
<div>
<strong>表示されるとこうなります。</strong>
<Child name={"ポール・マッカートニー"} year={1942} guitar={true} />
<Child name={"ジョン・レノン"} year={1940} guitar={true} />
<Child name={"ジョージ・ハリスン"} year={1943} guitar={true} />
<Child name={"リンゴ・スター"} year={1940} guitar={false} />
</div>
)
}
const Child = (props) => {
return (
<div>僕は{props.name}です。{props.year}年生まれです。{props.guitar ? 'ギターを弾けます。' : 'ギターは弾けません。'}</div>
)
}
//ここでpropsに対しての型定義を行っています。
Child.propTypes = {
name: PropTypes.string,
year: PropTypes.number,
guitar: PropTypes.bool
}
export default Parent;
prop-typesを導入する手順としては、
- PropTypesをimportする。
- コンポーネントのpropsに対して型定義を行う。
になります。
●動作確認
「name="リンゴ・スター"」の部分のyearとguitarの値を文字列に変えてみます。
import React from 'react';
import PropTypes from 'prop-types' //これをimportします。
const Parent = () => {
return (
<div>
<strong>表示されるとこうなります。</strong>
<Child name={"ポール・マッカートニー"} year={1942} guitar={true} />
<Child name={"ジョン・レノン"} year={1940} guitar={true} />
<Child name={"ジョージ・ハリスン"} year={1943} guitar={true} />
<Child name={"リンゴ・スター"} year={"1940"} guitar={"false"} /> {/* ここの値を間違ったもの(文字列)に変更 */}
</div>
)
}
const Child = (props) => {
return (
<div>僕は{props.name}です。{props.year}年生まれです。{props.guitar ? 'ギターを弾けます。' : 'ギターは弾けません。'}</div>
)
}
//ここでpropsに対しての型定義を行っています。
Child.propTypes = {
name: PropTypes.string,
year: PropTypes.number,
guitar: PropTypes.bool
}
export default Parent;
無事にエラーが吐き出されました。
■state
こちらが見本になります。
countというstateを持ったCounterコンポーネントを作成しました。
import React, { Component } from 'react';
class Counter extends Component {
// 状態を持たせるための処理
constructor(props) { // コンポーネントの初期化時に呼び出される
super(props)
// this.stateでstateにアクセスできる。
this.state = { count: 0 }
}
countUp = () => {
this.setState({ count: this.state.count + 1 }) // stateを変更する時は必ずsetState()を使用する。
}
countDown = () => {
this.setState({ count: this.state.count - 1 }) // stateを変更する時は必ずsetState()を使用する。
}
render() {
return (
<div className="counter">
<div>count:{ this.state.count }</div>
<button onClick={this.countUp}>+1</button>
<button onClick={this.countDown}>-1</button>
</div>
)
}
}
export default Counter;
以下、ポイントになります。
・レンダー制御が必要なのでクラスコンポーネントで作成した。
・stateの値を変更する時はsetState()を必ず使用する。
・this.stateでstateにアクセスする。
FORK Advent Calendar 2020
16日目 Full Static Generationを試す @AsaToBan
18日目 Reactで神経衰弱を作ってみた @ktn