やったこととか思ったこと

やったことを忘れないように気が向いたら書きます

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、CSSJavaScriptを組み込むことができます。

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を作っても、idhrefなどの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のみを含みます。

次に、CounterComponentを作ります。コードをを以下のようにしてください。

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のclicksstateを設定しましょう。

class Counter extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            clicks: 0
        };
    }
}
  • コンストラクタはComponentのpropsを受け取ります。
  • super(props)は親クラスのコンストラクタを呼び出します。(この場合はReact.Component)
  • clicksstateには、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>
  );
};

参考