🐥

[React🐣 ]宣言的UIの構築をシンプルなプロセスで理解する

2022/08/07に公開

この記事で話すこと

この記事ではReact入門者の方、UIの状態管理についてよく悩んでしまう人を対象に書いています。
いきなり複雑な状態管理を考え出すのではなく、そもそも宣言的UIの構築プロセスを頭の中に置いてそのコンポーネントの状態を特定し、整理することで管理する状態を明確にします☺️

宣言的UIの構築プロセスを通し、react入門・初心者がいきなり状態管理を考え出して手が動かなくなる状態を脱却することを目的にしています。

宣言的UIの構築をフォームコンポーネントを例に4STEPで理解する

今回は「入力値を送信するテキスト入力フォーム」を例にとって4stepでプロセスを理解する

  1. コンポーネントの状態を列挙してみる
  2. 状態変化のきっかけのトリガーを特定して、フローを作る
  3. useStateを使って状態を宣言する
  4. 状態のリファクタリング(今回は不要・重要でない状態変数を削除する)

目標:最初から状態管理のベストプラクティスを考えるのではなく、まずは宣言的UIの理解を深める。必要な状態を整理して、STEP4「状態のリファクタリング」という段階を設けることで管理すべき状態を明らかにすること。

STEP1コンポーネントの状態を列挙してみる

今回の入力フォームの状態は以下が考えられます
・Empty(未入力):フォームの「送信」ボタンが無効な状態
・入力中:フォームの「送信」ボタンが有効な状態
・送信中:入力は無効になっており、送信中の画面が表示されている状態
・成功:画面に「送信完了しました」のメッセージが表示される
・Error:画面に「送信失敗しました」のメッセージが表示される

上記で挙げた以外にも粒度を細かくすれば更に多くの状態を挙げられますが、最低限の状態を列挙することをまずは目標にするのがいいでしょう。ここでの最低限は画面上で視覚で確認できる状態を網羅できるまで列挙することdesu😎!

STEP2状態変化のきっかけになるトリガーを特定して、フローを作る

状態変化のトリガーは2種類に分けて考えられます

・ヒューマンインプット:人間による入力
・コンピュータ入力:コンピュータによる入力

例えば
人間による入力は「テキスト入力」「ボタンをクリック」
コンピュータによる入力は「HTTP リクエスト・レスポンスのやり取り」、「複雑な処理の計算」

😄「状態」を列挙しておくとデザイナー・クライアントさん達との共通認識を構築するための助けになるのでdraw.ioなどを使って整理しておくといいと思います。

😄UIの状態を足がかりに顧客達との共通認識を築き、それを踏まえてバックエンドの人とどのようにデータ構造に落とすべきかを考えるのも良いと思います。

💁🏻複数の状態をもつコンポーネントがある場合は、それらを1ページに列挙して表示すると共通認識のための理解を得るのに役立ちます!このページに似たものがツールとしてあるので気になる方は「ストーリーブック」などで検索してみてください!

import Form from './Form.js';//コンポーネントの状態をわかりやすく列挙したファイルlet statuses = [
  'empty',
  'typing',
  'submitting',
  'success',
  'error',
];export default function App() {
  return (
    <>
      {statuses.map(status => (
        <section key={status}>
          <h4>Form ({status}):</h4>
          <Form status={status} />
        </section>
      ))}
    </>
  );
}export default function Form({
  // Try 'submitting', 'error', 'success':
  status = 'empty'
}) {
  if (status === 'success') {
    return <h1>That's right!</h1>
  }
  return (
    <>
      <h2>City quiz</h2>
      <p>
        In which city is there a billboard that turns air into drinkable water?
      </p>
      <form>
        <textarea disabled={
          status === 'submitting'
        } />
        <br />
        <button disabled={
          status === 'empty' ||
          status === 'submitting'
        }>
          Submit
        </button>
        {status === 'error' &&
          <p className="Error">
            Good guess but a wrong answer. Try again!
          </p>
        }
      </form>
      </>
  );
}

STEP3useStateを使って状態を宣言する

状態は変化するものです。つまり、動的であるため状態が増えるほど考えるべきことは増えます。不要な状態が増えることは、更新忘れや考慮漏れの原因になりバグの発生を産むので、「状態」はできるだけ少なくすることを心がけましょう。

・「状態」はできるだけ少なくすることを心がける
・絶対にあるはずの状態から始める
・視覚的状態が確実にカバーできているか考える

絶対にあるはずの状態から始める。
たとえば、入力用にを保存し、最後のエラーを保存するために (存在する場合) を保存する必要があります

const [answer, setAnswer] = useState('');

const [error, setError] = useState(null);

初めは直ぐにベストな方法が見つからない場合がほとんどです。まずは可能なすべての視覚的状態が確実にカバーされるように、十分な状態を追加することから始めます。


const [isEmpty, setIsEmpty] = useState(true);

const [isTyping, setIsTyping] = useState(false);

const [isSubmitting, setIsSubmitting] = useState(false);

const [isSuccess, setIsSuccess] = useState(false);

const [isError, setIsError] = useState(false);

STEP4状態のリファクタリング(不要・重要でない状態変数を削除する)

重要かどうかを判断する際には下記を考慮するといいでしょう

・その状態が矛盾を引き起こすかどうか?

・その状態が同時に存在することができるかどうか

const [answer, setAnswer] = useState('');

const [error, setError] = useState(null);

const [status, setStatus] = useState('typing'); // 'typing', 'submitting', or 'success'

これら 3 つの状態変数は、このフォームの状態を十分に表しています。ただし、完全には意味をなさない中間状態がまだいくつかあります。状態をより正確にモデル化するために状態をreducer に抽出して複数の状態変数を単一のオブジェクトに統合して、関連するすべてのロジックを統合することもできます!

要約

宣言的UIでコンポーネント開発をする場合は:
1.  対象となるコンポーネントの状態を洗い出し列挙する(最低限:視覚的状態は網羅できるように)
2. 状態の変化のきっかけとなるトリガーを特定してフローを起こす
3. useStateで状態を宣言する
4. 不要・重要でない状態をリファクタリングする

Next

お疲れ様でした、宣言的UIでの最小単位のコンポーネントの構築プロセスが理解できたら次はコンポーネント間で状態をどのように共有するのか等を考えていきましょう!!
次のリファレンスで挙げたサイトのチュートリアルをやってみると更に理解が進むと思います🥳

良いね貰えると記事を書くモチベに繋がるので嬉しいです🥺!

Reference

https://beta.reactjs.org/learn/reacting-to-input-with-state#step-3-represent-the-state-in-memory-with-usestate
https://reactjs.org/docs/thinking-in-react.html
https://beta.reactjs.org/learn/thinking-in-react

Discussion