React を始める

忘備録の共有です

## 導入
[公式](https://ja.reactjs.org/docs/create-a-new-react-app.html)を参考にcliでインストールする。

```
npx create-react-app my-app
cd my-app
npm start
```

これで簡単にアプリの雛形が作れる。
ただ ./src 配下は階層化されているわけではないので、ここからお好みで改良していく必要がある。

### [■公式のおすすめする指針](https://ja.reactjs.org/docs/faq-structure.html)
一つは、ルートや機能ごとにjs、cssをまとめて突っ込む方法

```
common/
  Avatar.js
  Avatar.css
  APIUtils.js
  APIUtils.test.js
feed/
  index.js
  Feed.js
  Feed.css
  FeedStory.js
  FeedStory.test.js
  FeedAPI.js
profile/
  index.js
  Profile.js
  ProfileHeader.js
  ProfileHeader.css
  ProfileAPI.js

```

もう一つはファイルタイプ別に分ける方法

```
api/
  APIUtils.js
  APIUtils.test.js
  ProfileAPI.js
  UserAPI.js
components/
  Avatar.js
  Avatar.css
  Feed.js
  Feed.css
  FeedStory.js
  FeedStory.test.js
  Profile.js
  ProfileHeader.js
  ProfileHeader.css
```

このルールを突き詰めると Atomic Design になる。

### ■Atomic Design
流行りの設計
コンポーネントの粒度が揃って、慣れると楽そうだが慣れるまで苦労しそう
以下の様に、コンポーネントの粒度をカテゴライズして管理する
<dl>
<dt>Atoms（原子）</dt>
<dd>最小単位。ボタンやラベルなど、これ以上分割できないコンポーネントを指す</dd>
<dt>Molecules（分子）</dt>
<dd>Atoms を集めたコンポーネントを指す。例えばタイトルと写真、説明文を組み合わせたカードコンポーネントや記事の一セクションなど</dd>
<dt>Organisms（有機体）</dt>
<dd>Molecules を集めたコンポーネントを指す。ヘッダやフッダなど。</dd>
<dt>Templates（テンプレート）</dt>
<dd>ページ構造のこと。具体的に記事内容を入れたものではなく、コンポーネントの配置を定義している。ワイヤーフレーム</dd>
<dt>Pages（ページ）</dt>
<dd>具体的な記事などが入ったページ本体</dd>
</dl>

### ■どんな設計にするか(所感)
一人ならどの方法を選んでも構わないと思うが、多人数で行うプロジェクトならなるべく簡単な方法がいいと思う
特にatomic design を導入するときは、デザイナとの意思疎通もしておかないと実際にデザイナと協業しはじめた途端にトラブルが多発しそう

## 実装

### [■要素のレンダー](https://ja.reactjs.org/docs/rendering-elements.html)
HTML を出力するには React-DOM モジュールの render メソッドを使う。
create-react-app で生成されたアプリケーションの ./src/index.js で実際に使われている

```
前略
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);
後略
```

`<App />`が独自定義した要素。

忘れてはいけないのが、`/>`の部分で、React は閉じタグが無いとエラーを吐くので絶対に`/>`をいれること


### ■独自要素の定義
二種類の方法があり、要素を返すだけの関数で定義する方法と、ステートを持つクラスで定義する方法の二種類
今現在では独自ステートを持たせない方がいいとされ(使い回しが悪くなるためなどの理由)、関数で定義する方法が巷ではお勧めされている

#### 関数で定義する方法
create-react-app で生成したアプリケーションの ./src/App.js で、実際に関数で要素を定義している

```
前略
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.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;
```

これを見ると、単純に要素を返しているだけなのがわかる

また、React 16.8 から Hook (フック)と呼ばれる新しい要素が React に追加され、関数でもステートを持たせることができる様になった

#### クラスで定義する方法
React.Component クラスを継承することでクラスで定義できる様になる
以下例

```
import React from 'react'

class Welcome extends React.Component {
  render() {
    return <h1>Hello World</h1>
  }
}

export default Welcome
```

関数にしろクラスにしろ、ES6の定番でもあるが export するコンポーネントは1ファイル1つにして、ファイル名も export するコンポーネントと合わせた方がわかりやすい

また、return する要素の一番親要素は一つでないといけないルールがある

### [引数を取る](https://ja.reactjs.org/docs/components-and-props.html)
独自定義したタグにプロパティを定義してあげると、定義したタグの引数にkey-valueのオブジェクト形式で渡される
渡す側

```
<App name="hoge" />
<Welcome  name="hoge" />
```

渡される側(関数)

```
前略
function App(props) {
  return (
    <div className="App">
      <p>Hello, {props.name}</p>
後略
```

渡される側（クラス）

```
前略
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>
後略
```

### ■ステートを持たせる
従来ステートを持たせるにはクラスを使うしかなかったが、React 16.8 からフック機能が追加されたため関数でもステートを持たせることができる
redux という react のステート管理をするためのフレームワークを使う手もあるが、この記事では言及しない

#### [Hook](https://ja.reactjs.org/docs/hooks-overview.html)
まずは hook を使う方法

```
import React, {useState} from 'react';

function App(props) {
  const [count, setCount] = useState(0)
  return (
    <React.Fragment>
      <button onClick={() => setCount(count + 1)}>CLICK ME</button>
      <p>{count}</p>
    </React.Fragment>
  );
}

export default App;
```

Hook で重要な関数が useState で、現在の state の値と、それを更新するための関数をペアにして返す
上記の例でいうと、count という値を定義とそれを更新するための setCount を定義し、引数の 0 で count の値を初期化している

そして button の onClick イベントのコールバックで setCount を呼んで state を更新している

これが簡単な Hook の使い方


#### クラス使う方法
次に従来のクラスを使う方法

```
import React from 'react'

class Welcome extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }
  }
  onClick() {
    this.setState({
      count: this.state.count + 1
    })
  }
  render() {
    return (
      <React.Fragment>
        <button onClick={this.onClick.bind(this)}>CLICK ME</button>
        <p>{this.state.count}</p>
      </React.Fragment>
    )
  }
}

export default Welcome
```

早速ステートとは関係のないことだが、constructor で super(props) しているのは定型文の様なものなので、クラス構文でコンポーネントを定義して constructor を書く必要があるときは必ず書くこと

上記の例では constructor で

```
this.state = {
  count: 0
}
```

としているところがステートを初期化しているところ。インスタンスの state プロパティにオブジェクトを渡すことで初期化できる。
上記の例で言うと、count と言う名前のステートを 0 で初期化している。

ステートの更新は、setState メソッドで行う。直に更新してはいけない。

```
this.setState({
  count: this.state.count + 1
})
```

### ■CSS, 画像
import して使う。 create-react-app で作ったアプリケーションの ./src/App.js を参照

#### styled components
よく react と組み合わせて使われている CSS in JS のライブラリの一つ

■使い方
まずは styled-components をインストールする

```
npm install --save styled-components
```

スタイルの定義を行う。` styled.タグ名｀スタイルの定義｀ `で定義できる

```
import styled from 'styled-components'
const IncrementButton = styled.div`
    // ここにスタイルの定義
    border: 1px solid #333;
    background-color: #fff;
    cursor: pointer;
    display:inline-block;
    padding: 4px;
`;
```
定義したスタイルを使う

```
<IncrementButton onClick={() => setCount(count + 1)}>CLICK ME</IncrementButton>
```

### ■ページ遷移
ページ遷移には react-router を使う。
インストール

```
npm install --save react-router-dom
```

次に最低限必要なモジュールをインポートする

```
import {Link, BrowserRouter as Router, Route} from 'react-router-dom'
```

Router の中に Link と Route を入れる
Link の to 属性にパスを定義する。この Link が a タグになる
Route には path とその path に対応する component を定義する

```
<Router>
  <Link to="/">Main</Link>
  <Link to="/About">About</Link>
  <Route exact path='/' component={Main} />
  <Route path='/About' component={About} />
</Router>
```

なお、'/' の path を定義している Route に設定している exact は、パスの部分一致を否定する属性で、これがないと全てのルートがヒットしてしまう

### 繰り返し
配列に Dom を入れ、その配列を展開する形で繰り返しを表現できる

```
// 配列を用意する
const ActionButtons = []

// 配列に要素を入れていく
for (let i in props.data) {
  ActionButtons.push(<button title={props.data[i].title} path={props.data[i].path} />)
}

return (
  <Div>
    // 配列変数を展開する
    {ActionButtons}
  </Div>
)
```

### 条件付きレンダー
渡された式を評価して、真だったときだけ要素をレンダーする機能。vueで言うところのv-ifやv-show

```
{ここに条件式 &&
  // ここに特定条件でレンダー死体要素
  <h2>
    ほげほげ
  </h2>
}
```


## 雑記
他に必要なことが合ったら順次追記していきます