1つの行で状態機械をタイプスクリプトで書く


ああはい、州のマシン.そのことはツイートを続けます、あるいは、そのCS概念は学期に一度大学に現れます(そして、一見しないでください…).フロントエンド・ワールドがReduxでますますdisatisfiedされるように、状態機械はそうですone of many concepts DEVSは最近話しています.
しかし、reduxらとは異なり、状態機械はあなたがあなたのプロジェクトにインストールするライブラリである必要はありません!一旦それらを概念的に理解するならば、彼らは問題についての彼ら自身の方法になります.
要するに、この記事はあなたを助けるべきです.
  • ブールフラグと状態変数が複雑過ぎる
  • ライブラリを使用して独自のscrappy状態機械を書く
  • 概念としての状態機械についてもう少し学び、Xstateが良い考えであるかもしれないとき
  • 以降!
    ⚠️ 注意:以下の例では、反応を使用します.それでも、コア学習概念はどんなフロントエンドフレームワークにも移します

    まず、シナリオ


    私たちがUIの複雑さを話しているなら、フォーム管理は見る最も簡単な場所です.我々は我々がユーザー名とパスワードで実装する必要がある画面を簡単にサインアップしているとしましょう.物事を少しおもしろくするために、私たちは信じられないほどの幼い頃の記憶を復活させていると言いましょうClub Penguin !

    こわがらないようにしなさい.少なくとも、それはFlash😬
    また、ユーザーがフォームを塗りつぶすなど、いくつかのシナリオを考えたいと思います.つまり、提出する前にパスワード検証を行う必要があります.以下のような流れです.

    一般的なアプローチ:ブルートフォース


    まず、DEVSの多くのアプローチをカバーしましょう(especially coming from a Redux background) . 我々が望む対話に基づいて、我々は多分いくつかの旗を持っているべきです
  • パスワードが無効な場合
  • 我々がAPIに提出しているとき
  • 我々が首尾よく提出したかどうか(多分次のスクリーンに動くかもしれません)
  • 私たちが必要とするHTML +カラフルなCSSであなたを退屈させませんCodeSandbox このようなグッズには、それで、ちょうど我々が気にかける部分を見ましょう
    const ClubPenguinSignup = () => {
      const [invalid, setInvalid] = React.useState(false);
      const [submitting, setSubmitting] = React.useState(false);
      const [submitted, setSubmitted] = React.useState(false);
      ...
      // state vars for username and password, markup, etc.
    }
    
    提出/送信フラグについては、フォームが送信されるたびにniceコールバック関数を使用できます.
    const onSubmit = async (event: React.FormEvent) => {
      event.preventDefault();
      setSubmitting(true); // we're now submitting
      const addedUser = await arcticAuthService({ username, password });
      if (addedUser?.success) { // if signup call worked...
        setSubmitting(false); // we're no longer submitting
        setSubmitted(true); // we've submitted
        }
    };
    
    最後に、我々は、ユーザーが入力するように我々のパスワードを検証するための超基本的なコールバックを作ることができます.この場合、入力の値が変わるたびにcontrolled input ), そして、安全でないフレーズチェッカーを通して値を実行します.
    const onChangePassword = (event: React.FormEvent<HTMLInputElement>) => {
      setPassword(event.currentTarget.value);
      checkPasswordSecurity(event.currentTarget.value);
    };
    
    const checkPasswordSecurity = (changedPassword: string) => {
      let insecure = false; // we first assume the value is secure (excuse the double negative)
      ["club", "penguin", "puffle"].forEach((badWord) => {
        if (changedPassword.includes(badWord)) {
          insecure = true;
        }
      });
      setInvalid(insecure);
    };
    

    毛むくじゃらが始まるところ


    すごい!これはあまり悪くないようです.しかし、我々はまだしていません.あなたが再びそのモックアップをチェックするならば、あなたは我々のボタンが表示するために3つの異なる指標を持っていることに気がつきます.これらのそれぞれに対して別々のブールフラグを使用しているので、ボタン背景+風味テキストを設定するためのマッパが必要になります.
    const getButtonLabel = (): string => {
      if (submitting) {
        return "•••";
      } else if (submitted) {
        return "Time to play!";
      } else {
        return "Let's get sliding!";
      }
    };
    
    const getButtonClass = (): string => {
      if (submitting) {
        return "submitting";
      } else if (submitted) {
        return "submitted";
      } else if (invalid) {
        return "invalid";
      } else {
        return "";
      }
    };
    
    return (
        ...
      <button type="submit" className={getButtonClass()}>
        {getButtonLabel()}
      </button>
    )
    
    私たちは単一の要素のためにmappersを必要とするだけであるので、これはひどいようでありません.しかし、私たちがより多くのUIとより多くの状態変数を加えるとき、これは簡単に制御から気球を開始することができました.
    const [usenameTaken, setUsernameTaken] = React.useState(false);
    const [apiError, setApiError] = React.useState(false);
    const [serverAtMaxCapacity, setServerAtMaxCapacity] = React.useState(false);
    const [invalid, setInvalid] = React.useState(false);
    const [submitting, setSubmitting] = React.useState(false);
    const [submitted, setSubmitted] = React.useState(false);
    
    const getButtonClass = (): string => {
      // 100 lines of ifs
    };
    
    我々はまた、可能ではない多くの州を許可している.例えば、我々は同時に「提出」と「提出」してはいけません、そして、これらのどちらもtrue パスワードが不正な場合.上記の狂った状態爆発を考慮して、我々はこれらの無効な状態を防ぐためにすべてのこれらの変数を落ち着かせます.
    // api responds that servers are at max capacity, so no sign ups allowed
    setServerAtMaxCapacity(true)
    setSubmitting(false)
    setSubmitted(false)
    setApiError(true)
    ...
    
    何かあれば、2つ以上の値を持つブールを持ちたいので、私たちはすべての場所にフラグを切り替えません.幸運にも、タイプスクリプトは我々にそのような超大国を与えます💪

    私たちの新しいアプローチ:貧しい男性の国家機械


    あなたが推測したかもしれないように、我々は単純な状態機械でこのBoolean Bananzaを解決することができます.私はこのアプローチは、“”としても、超aptのタイトルであると呼ばれる聞いたことがある!
    私たちが必要とするのは、xstateライブラリが一つのタイプとして状態変数をモデル化するための1つのライナーです.
    type FormState = 'idle' | 'invalid' | 'submitting' | 'submitted'
    
    あなたは確かにこれのためにenumを使うことができました.私は、彼らが少しより短い+より読みやすい(ちょうどあなたがまだenumスタンであるならば、私も書きました)ので、文字列リテラルを好みます.
    定義された型で、すべての状態変数を1つに凝縮できます.
    const [formState, setFormState] = React.useState<FormState>("idle");
    
    パスワードをリファクタリングしてコールバックを送信するのはここからかなり簡単です.
    const checkIfPasswordIsSecure = (changedPassword: string) => {
        setFormState("idle"); // not invalid yet
        ["club", "penguin", "puffle"].forEach((badWord) => {
          if (changedPassword.includes(badWord)) {
            setFormState("invalid"); // oops! Looks like it's invalid after all
          }
        });
      };
    
    const onSubmit = async (event: React.FormEvent) => {
      event.preventDefault();
      if (formState === "invalid") return; // don't submit if our password is invalid
      setFormState("submitting");
      const addedUser = await arcticAuthService({ username, password });
      if (addedUser?.id) {
        setFormState("submitted"); // no need to set submitting to false, since we don't have 2 states to consider anymore!
        }
    };
    
    そしてそれらのボタンをclassName 我々がマップする必要があったs?さて、私たちの状態は文字列として表現されているので、私たちは単に✨
    return (
        <button type="submit" className={formState /* our state is our CSS */}>
            ...
      </button>
    )
    
    このアプローチは、チェックのCSSを維持するためのスーパー便利ですクラスを常に追加したり削除したりする代わりに、どのクラスを適用するかを切り替えることができます.
    Here's a working CodeSandbox 新しいアプローチの使用✨

    更なる🚀


    もちろん、これはあなたのユースケースにかなり適合しないかもしれないかなり簡単な例です.たとえば、指定された時刻に複数の状態になりたい場合や、「無効な遷移」に対してガードすることができますidle to submitted 通過することなくsubmitting はじめに
    前者は複数の状態変数を必要とするので、複数のFormState タイプをどのように感じを参照してください.それでも、あなたは国家管理ライブラリが多くの感覚を作るのに十分な複雑さを持つかもしれません.チェックアウトXState これがあなたのように聞こえるならば!
    あなたの足を湿らせるために、私はインターネットをチェックする価値がある2つの高品質デモを見つけました:

  • より複雑なreactjsのフォームを構築する.それは長いが、あなたの時間の価値がある!

  • バニラJSドラッグアンドドロップの相互作用を作成する.これは、より多くのCSSの集中とclassName 上に見せたトリック.

  • フレームワーク間の状態機械によるUIのモデル化件名ダウンベスト会議トークダウン.
  • 少し何かを学ぶ?


    グルービー.あなたがそれを逃した場合はmy "web wizardry" newsletter このような知識ナゲットを探索する!
    このことは"first principles" Web開発言い換えれば、すべてのJankyブラウザAPI、曲げられたCSS規則、およびすべてのWebプロジェクトをティックにするセミアクセス可能なHTMLは何ですか?あなたがフレームワークを越えて行くことを探しているならば、これはあなたのためです🔮
    Subscribe away right here . 私はいつも教えて、決してスパム❤️