Frontend Bootcampを読む Step1-04
Microsoftが公開していたFrontend Bootcampを 1-04から読み進めていくメモ
自分なりの適当な翻訳なので間違いがあるかもしれません。
また公開されたばかりで現在進行形で更新されているので僕が読んだ時とは内容が少し変わっているかもしれません。
上のリンクのREADMEに沿って環境を整えてください。
Step1-04: Introduction To React Demo
このデモでは、クリック数とカウントを表示するシンプルなカウンターを作ります。
CodePenを使って始めましょう。
React Hello World
ReactDOM.render(<p>Hello World</p>, document.getElementById('app'));
ReactDOM.render()
この関数を使ってコードを表示します。2つのパラメータを取ります。
1つはページに配置するコンテンツ(ここでは
<p>Hello World</p>
)2つ目はコンテンツを配置したい場所(ここでは
document.getElementById('app')
)です。
Writing React Component
ReactのComponentはアプリケーションの一部を返すコードです。これには、HTML、CSS、JavaScriptを組み込むことができます。
Componentは2つの方法で作成することができます。
1つはReact.Component
クラスを継承するJavaScriptのクラスを利用する方法です。
JavaScriptのクラスは、拡張可能なコンテナ内にメソッド(関数)とProperties(値)を集めることができます。React.Componentは、renderを含むいくつかのメソッドを使えるようにするので、拡張しています。
class App extends React.Component { render() { return <p>Hello World</p>; } }
Componentは、propsを受け取ってJSXを返す関数として書くこともできます。
const App = props => { return <p>Hello World</p>; };
Hello World
をAppのrenderに移動したので、`ReactDOM.Render()を次のようにできます。
ReactDOM.render(<App />, document.getElementById('app'));
React Componentは、HTMLタグと同じように記述することで再利用できます。
Props
どちらの方法でComponentを作っても、id
やhref
などのHTML属性と同じ構文を利用して追加のpropsを取り込むことができます。
<App text="Hello World" />
propsはComponentから、関数のprops.text
、またはクラスのthis.props.text
を通してアクセスすることができます。
// 関数の場合 const App = props => { return <p>{props.text}</p>; }; // クラスの場合 class App extends React.Component { render() { return <p>{this.props.text}</p>; } }
propsを使うと、同じComponentの複数のインスタンスを異なるpropsで使うことができるため、Componentをより再利用しやすくなります。
ReactDOM.render( <div> <App text="Hello World" /> <App text="How are you doing?" /> </div>, document.getElementById('app') );
レンダリングする関数は1つの要素しか返すことができないため、2つのApp Componentをdivでラップする必要があります。
const App = props => { <p>{props.text ? props.text : "oops!"}</p>; };
Destructuring Props
関数内でprops.text(またはクラス内でthis.props.text)を繰り返し書くのは冗長です。なので、textに変数を割り当てることができます。
const App = props => { const text = props.text; return <p>{text ? text : 'you missed something'}</p>; };
これは、単一のpropsに対しては便利です。しかし、Componentが複雑になるにつれてコードはこうなります。
<MyComponent open={false} count={5} text="Hi there" items={['cat', 'dog', 'bird']} config={{ start: 1, end: 10, autoStart: true }} /> // Component内 const open = props.open; const text = props.text; const count = props.count; const items = props.items; const start = props.config.start; const end = props.config.end;
string以外の値は全て{}で囲んでJavaScriptとして渡します。
destructuringを使うことによって複雑なデータ型から個々の情報を1行で取り出すことができます。
const { open, text, count, items, config: { start, end } } = props;
今のはやり過ぎかもしれませんが、propsを追加することは簡単です。
const App = props => { const text = props.text; return <p>{text ? text : 'you missed something'}</p>; };
Cleanup
先に進む前に、ReactDOM.render
をリセットしてAppを返すだけにします。このReactDOM.render
関数は基本的にの無い単一のComponentのみを含みます。
次に、Counter
Componentを作ります。コードをを以下のようにしてください。
const App = props => { return <Counter text="chickens" />; }; ReactDOM.render(<App />, document.getElementById('app'));
Counter
の大文字に気をつけてください。HTMLの場合は大丈夫ですが、JSXでは区別します。React Componentの名前は一般的には対応するHTML要素の大文字の名前を使用することです。(Button, Select, Label, Formなど)
React State
Reactはstateというデータストアを各コントロールに指定することができます。UIをレンダリングするときに、stateの値を参照できます。また、アプリケーションが有効な間にstateを更新することもできます。
最近、Hooksという関数Componentにstateを追加する機能が追加されましたが、今現在見られるステートフルComponentのほとんどがクラスベースです。
Adding State
JavaScriptのクラスはconstructor
を利用してクラスをstateと共にインスタンス化します。それでは、Counter
という新しいComponentを作り、デフォルト値が0のclicks
stateを設定しましょう。
class Counter extends React.Component { constructor(props) { super(props); this.state = { clicks: 0 }; } }
- コンストラクタはComponentのpropsを受け取ります。
super(props)
は親クラスのコンストラクタを呼び出します。(この場合はReact.Component
)clicks
stateには、this.state.counter
を呼ぶことですぐにアクセスできます。また、this.setState({ clicks: 1 })
を呼び出すことによってstateを更新することもできます。
Creating out Counter
Counter Componentの目標は、clicksのボタンがクリックされた回数を追跡できるようにすることです。以下のコードを書き込みます。
render() { const { text } = this.props; const { clicks } = this.state; return ( <div> {text}: {clicks} <button>Click</button> </div> ) }
Writing our Button Click Handler
次のステップは、ボタンを押すとclickが増えるようにすることです。
慣例で、他のメソッドはrender()の下に配置されます。また、privateなメソッドはメソッド名の前にアンダースコアがつきます。
このメソッドはComponentのstateを更新し、1づつclicksの値を増やします。(setStateはオブジェクトの値のみを変更します。)
_onButtonClick = () => { this.setState({ clicks: this.state.clicks + 1 }); };
前の値が決定されるまでstateを更新しないように
this.setState(prevState => ({ counter: prevState.clicks + 1 });
と書くこともできます。
カウントを増やせるようになったので、ボタンに接続しましょう。
<button onClick={this._onButtonClick}>Click</button>
各Counterは、自身のstateを維持しています。なので、他の Counterに影響を与えずに、1つのCounter内のstateを変更できます。
Try it all out!
それぞれ異なるtextを使用してアプリのカウンターを2つにします。それらが自身のstateを維持していることがわかります。
Module Exports and Imports
step1-04/final/components/Counter.tsx
を開き、Counter Componentを見てください。
export class Counter extends React.Component { ... }
このファイルはCounter Componentを'named'エクスポートとしてエクスポートしています。これは次のようにインポートします。
import { Counter } from './components/Counter';
Default Exports
通常はnamedエクスポートを使いますが、次のようにデフォルト値をエクスポートすることもできます。
export default class extends React.Component { ... }
この場合、エクスポートに名前がないので、Componentをインポートするときに、好きなように名前をつけることができます。
import SomeCounterComponent from './components/Counter';
上の例ではインポート値を{}でラップしていません。これは実際には破壊的な例です。
Using a Button component
ボタンは最も一般的にかかれたComponentの1つです。カスタムボタンは、一般的なスタイルを抽象化したり、アイコンやその他の装飾を追加したり、メニューボタンなどの機能を増やすことができます。カスタムComponentを見てみましょう。
import React from 'react'; import './Button.css'; export const Button = props => { return ( <button className="Button" onClick={props.onClick}> {props.children} </button> ); };