Open11

Reactメモ

Kohki_TakatamaKohki_Takatama

useState(stateフック)

構文

function ImageGallery() {
  const [index, setIndex] = useState(0);
  // ...
  • sethogeで「変数の値の更新」と「表示の更新」が可能
  • const宣言が一般的(setを通さない直接代入を防ぐため?)
  • useState()に引数を渡すのは初期値を設定する時だけ?

props

親から子へ受け渡すもの
useContextを使用すると孫以上でも直接の受け渡しが可能

useRef(refフック)

構文

function Form() {
  const inputRef = useRef(null);
  // ...
  • stateと違い、refの値を更新してもコンポーネントの再レンダは起こらない
  • Reactパラダイムからの「避難ハッチ」として、React外のシステムを扱う時に役立つ
  • 具体的には、DOMノードなどを格納する
Kohki_TakatamaKohki_Takatama

Reactにおける「コンポーネント」とは

https://ja.react.dev/learn

React アプリはコンポーネントで構成されています。コンポーネントとは、独自のロジックと外見を持つ UI(ユーザインターフェース)の部品のことです。

React におけるコンポーネントとは、マークアップを返す JavaScript 関数です。

React のコンポーネント名は常に大文字で始める必要があり、HTML タグは小文字でなければなりません。

function MyButton() {
  return (
    <button>I'm a button</button>
  );
}
export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
    </div>
  );
}

<MyButton /> が大文字で始まっていることに注意してください。

まとめ:コンポーネント = マークアップを返すJS関数

  • コンポーネントは大文字
  • HTMLタグは小文字
  • コンポーネントは、別のコンポーネントにネストできる

JSX

  • タグは閉じる必要がある(例:<br />
  • returnできるのは単一のタグ(よって、<>...</>で囲んだりする)
function AboutPage() {
  return (
    <>
      <h1>About</h1>
      <p>Hello there.<br />How do you do?</p>
    </>
  );
}
  • classはclass属性ではなくclassName属性(例:<img className="avatar" />
  • {}を使うことで、JSとリンクできる。
return (
  <h1>
    {user.name}
  </h1>
);

// {"hoge" + "fuga"} などの演算も可能
  • 条件分岐の特別な構文&&
<div>
  {isLoggedIn && <AdminPanel />}
</div>

// 以下と(ほぼ)同一

let content;
if (isLoggedIn) {
  content = <AdminPanel />;
}
return (
  <div>
    {content}
  </div>
);
  • useStateを使用するにはimportが必要(import { useState } from 'react';
    • useStateはインスタンス的で、それぞれが異なる状態を保持する(例:ボタンのクリック回数)
Kohki_TakatamaKohki_Takatama

Hook

https://ja.react.dev/learn

use で始まる関数は、フック (Hook) と呼ばれます。

フックには通常の関数より多くの制限があります。フックはコンポーネントのトップレベル(または他のフック内)でのみ呼び出すことができます。条件分岐やループの中で useState を使いたい場合は、新しいコンポーネントを抽出してそこに配置します。

Kohki_TakatamaKohki_Takatama

useState テクニック

「別のボタンでも同じ状態を保持したい」場合

「ボタンごとに状態を持つ」のではなく。

https://ja.react.dev/learn#sharing-data-between-components

🙅‍♂️ 🙆‍♂️

まず、MyButton から MyApp に、state の移動を行います。

export default function MyApp() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <h1>Counters that update separately</h1>
      <MyButton />
      <MyButton />
    </div>
  );
}

function MyButton() {
  // ... we're moving code from here ...
}

次に、MyApp から各 MyButton に state を渡し、共有のクリックハンドラも一緒に渡します。以前に <img> のような組み込みタグで行ったときと同様、JSX の波括弧を使うことで MyButton に情報を渡すことができます。

export default function MyApp() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <h1>Counters that update together</h1>
      <MyButton count={count} onClick={handleClick} />
      <MyButton count={count} onClick={handleClick} />
    </div>
  );
}

このように渡される情報は props と呼ばれます。MyApp コンポーネントは count 状態と handleClick イベントハンドラを保持しており、それらをどちらも props として各ボタンに渡します。

最後に、MyButton を変更して、親コンポーネントから渡された props を読み込むようにします。

function MyButton({ count, onClick }) {
  return (
    <button onClick={onClick}>
      Clicked {count} times
    </button>
  );
}
Kohki_TakatamaKohki_Takatama

Reactの流儀📝

https://ja.react.dev/learn/thinking-in-react

◆ 実装の順番

1. コンポーネントに分解

まず最初に行うのは、モックアップのすべてのコンポーネントとサブコンポーネントを四角で囲んで、それぞれに名前を付けていくことです。

2. 静的なバージョンを作成

引用とテクニック

アプリの実装に取り掛かりましょう。最も分かりやすいアプローチは、インタラクティブな要素はまだ加えず、単にデータモデルから UI をレンダーするバージョンを作成することです。

通常、単純な例ではトップダウンで作業する方が簡単であり、大規模なプロジェクトではボトムアップで進める方が簡単です。

3. 最小限のUI設計

state / props / そこから計算されるもの に分割する。何をstateとするかは後述。

4. stateを保持するコンポーネントを特定

特定方法の例
  1. そのstateに基づいたレンダーを行う「すべてのコンポーネント」を特定する
  2. それらの最上位コンポーネントを見つける
  3. そのコンポーネント / より親のコンポーネント / 新規コンポーネント を適切に選択しstateを保持させる

5. 子→親のデータフローを追加する

stateであれば、setState関数を渡すこと

function FilterableProductTable({ products }) {
    const [filterText, setFilterText] = useState('');

    // ~~~
    return (
        <div>
          <SearchBar 
            filterText={filterText} 
            onFilterTextChange={setFilterText} />
function SearchBar({...}) {
    return {
        <input
            type="text"
            value={filterText}
            placeholder="Search..."
            onChange={(e) => onFilterTextChange(e.target.value)}
        />
    }
}

stateを使用する判断基準

  • 時間が経っても変わらないものですか? そうであれば、state ではありません。
  • 親から props 経由で渡されるものですか? そうであれば、state ではありません。
  • コンポーネント内にある既存の state や props に基づいて計算可能なデータですか? そうであれば、それは絶対に state ではありません!

-> 「変化する」「渡されない」「計算不可能な」データにstateを使う

Kohki_TakatamaKohki_Takatama

命名規則等

https://qiita.com/shuhosaka/items/4a11158b3e9060d3b612

React

◆ Rule

  • ひとつのファイルにひとつのコンポーネント
    • 複数のステートレス・単純なコンポーネントはまとめることを許容する
  • デフォルトエクスポートでもコンポーネントに名前をつける

◇ 命名規則

  • Reactコンポーネント:アッパーキャメル
  • インスタンス:ローワーキャメル?
インスタンスとは?(推測)
import React from 'react';

// パスカル記法: コンポーネントの定義
const MyComponent = ({ name }) => {
  return <div>Hello, {name}!</div>;
};

// キャメル記法: インスタンス化して使用
const myComponentInstance = <MyComponent name="Jane" />;

export default function App() {
  return (
    <div>
      {myComponentInstance}
    </div>
  );
}
  • ファイル名 = コンポーネント名
  • 短く・直感的で・説明的(S-I-D)
  • 単語の短縮は避ける
  • Prefix? / Action / High Context / Low Context パターン(A/HC/LC Pattern)

◆ A/HC/LC Pattern

例:get / User / Messages

Prefix?

主に変数の意味を強化する。

  • is bool
  • has bool
  • should bool:条件分岐の判定条件として使う
function shouldUpdateUrl(url, expectedUrl) {
  return url !== expectedUrl
}

if(shouldUpdateUrl(a, b)) {
    // update url
}
  • min / max num:制限・境界を明示
  • prev / next:前後関係を明示。状態遷移の文脈
  • 単数 / 複数

Action

  • get
  • set
  • reset
  • remove / add
  • delete / create
  • compose:既存のデータから新しいデータを作成
function composePageUrl(pageName, pageId) {
  return pageName.toLowerCase() + '-' + pageId
}
  • handle:callback
Kohki_TakatamaKohki_Takatama

そもそもReactについて

開発元:Meta

2011年 Facebook内部で利用開始
2013年 OSSとして公開

Reactの特徴

  • viewに特化→「ライブラリ」と自称
  • コンポーネント指向
    → Model / Controller は不要 → サーバーを通さず、フロントで終始できる。
  • JSX(必須ではない)→当時は不評だった。HTML/CSS/JSを分けるほうが良いとされるため
  • 宣言的UI(what)(対義語:命令的(how))
  • 仮想DOM→現実のDOMは遅いことが多い
    ただし、最適化方法の一つであり、これを使うことで遅くなることもある。
    また、現在のreactは仮想DOMとは呼ばない。react nativeなど仮想domを使わない環境もあるため。
    ドキュメント上は「reactツリー」と呼ばれている
    なお、差分検出機能は「reconciliation」と呼ばれている
  • Learn Once, Write Anywhere(ネイティブアプリでも、的な意味?)
    間違ったベストプラクティスを押し付けない→フォルダ構成など

デメリット

View以外をどうするかはアプリ開発側で考える必要がある
(ユーザー権限などを、reduxなどのサードパーティに頼らないといけない)