私が何を言いたいのか


反応の2年後に私はいくつかの経験を共有したいと思います.あなたがちょうど反応を始めたならば、私はこの記事があなたが1 - 5のフォームから構成要素の巨大なセットにあなたのプロジェクトを開発する正しい方法を選ぶのを助けて、混乱しないように願っています.
あなたがすでにプロであるならば、おそらくあなたの欠点を覚えていてください.または、おそらく、説明された問題により良い解決を提案する.
この記事は、コンポーネントの構成をどのように整理するかという私の個人的な意見について話します.

始めましょう
抽象的な形を考えましょう.私たちは、フォームが多くのフィールド(約10 - 15)を持っていると仮定しますが、あなたの目を開いておくために、例として4フィールドでフォームを取りましょう.
この種のマルチレベルオブジェクトは、コンポーネントの入力に到達します.
const unit = {
  name: 'unit1',
  color: 'red',
  size: {
    width: 2,
    height: 4,
  },
}
未熟な開発者(私の最初の1ヶ月間で動作するように)は、すべての値を入力します.
const Component = ({ values, onSave, onCancel }) => {
  const [ state, setState ] = useState({});

  useEffect(() => {
    setState(values);
  }, [ values, setState ]);

  return <div className="form-layout">
    <div className="form-field">
      <label>Name</label>
      <div className="input">
        <input onChange={({ target: { value } }) =>
          setState((state) => ({...state, name: value }))
        }/>
      </div>
    </div>
    <div className="form-field">
      <label>Color</label>
      <div className="input"> 
        <input onChange={({ target: { value } }) =>
          setState((state) => ({...state, color: value }))
        }/>
      </div>
    </div>
    <div className="size">
      <div className="block-label">Size</label>
      <div className="form-field">
        <label>Width</label>
        <div className="input">
          <input onChange={({ target: { value } }) =>
            setState((state) => ({...state, size: { width: value } }))
          }/>
        </div>
      </div>
      <div className="form-field">
        <label>Height</label>
        <div className="input">
          <input onChange={({ target: { value } }) =>
            setState((state) => ({...state, size: { height: value } }))
          }/>
        </div>
      </div>
    </div>
    <div className="buttons">
      <button onClick={() => onSave(state)}>Save</Button>
      <button onClick={() => onCancel()}>Cancel</Button>
    </div>
  </div>
}
開発者がどれほど迅速に対処したかを見ると、お客様はこのフォームに基づいて作ることを提案します.
const unit = {
  name: 'unit1',
  color: 'red',
}
そして、2つのオプションがあります(両方とも間違っています).
  • あなたは最初のコンポーネントをコピーすることができますし、何が不足しているか、不要なものを削除します.これは通常、コンポーネントが自分自身ではなく、何かを壊すのが怖いときに起こります.
  • 追加のコンポーネント設定をパラメーターに追加します.
  • 3 - 5の形態の実装の後、プロジェクトは終わっています、そして、開発者は幸運です.
    しかし、これは通常最初の始まりです、そして、異なる形の数は成長しているだけです..
    それから、同様のものが必要です、しかし、「色」ブロックなしで.
    その後、同様のものが、新しい“説明”ブロックで.
    次に、いくつかのブロックを読み取り専用にする必要があります.
    次に、同様のフォームを別のフォームに挿入する必要があります

    コピーによる新しい形
    もちろん、コピー方法を選ぶ開発者は、すぐに、新しいフォームの実装に対処します.それらのうちの10未満がある限り.しかし、気分が徐々に落ちる.
    特に再設計が起こるとき.フォームブロック間のインデントを修正することができます“少し”、色の選択コンポーネントを変更することができます.結局のところ、すべてを一度に予言することはできませんし、多くのデザインの決定は、その実装後に再考する必要があります.
    ここでは“似たような形式”への頻繁な参照に注意を払うことが重要です.結局のところ、製品は1つであり、すべてのフォームが似ている必要があります.結果として、各フォームで同じことをやり直すという非常におもしろくて日常的な仕事をしなければなりません.また、テスターでは、各フォームを再チェックする必要があります.

    In general, you get the point. Do not copy similar components.



    一般化による新しい形
    開発者が第2の方法を選んだならば、もちろん、彼がゲームの上にあると、あなたは考えます.彼は数十の形態を描くことができるいくつかの成分しか持っていない.プロジェクト全体でインデントを修正するには、「色」コンポーネントを変更するには、コードの2行を修正する必要があります.
    しかし、実際には、この方法は非常に複雑なコンポーネントを作成しました.
    多くのパラメータがあるので、それを使用するのは難しいです.そして、いくつかにはほとんど同じ名前があります.
    <Component
      isNameVisible={true}
      isNameDisabled={true}
      nameLabel="Model"
      nameType="input"
      isColorVisible={true}
      isColorDisabled={false}
      colorType={'dropdown'}
      isSizeVisible={true}
      isHeightVisible={true}
      isWidthDisabled={false}
    />
    
    また、維持するのは難しいです.原則として、内部の複雑な絡み合った条件があり、新しい条件を追加すると他のすべてを破ることができます.1つのフォームを出力するコンポーネントを調整すると、他のすべてを破ることができます.

    Anyway, you get the point. Don’t make a component with a lot of properties.


    第2のオプションの問題を解決するために、開発者は何を始めますか?そうです.本当の開発者のように、彼らは複雑なコンポーネントの構成を簡素化する何かを開発し始めます.
    例えば、彼らはパラメータフィールド(反応テーブルの列のような)を作ります.そこにフィールドパラメータを渡します.フィールドは表示できません.
    コンポーネントコールは次のようになります.
    const FIELDS = {
        name: { visible: true, disabled: true, label: 'Model', type: 'input' },
        color: { visible: true, disabled: false, type: 'dropdown' },
        size: { visible: true },
        height: { visible: true },
        width: { disabled: false },
    }
    <Component
      values={values}
      fields={FIELDS}
    />
    
    その結果、開発者は自分自身を誇りに思います.彼はすべてのフィールドの設定を一般化し、コンポーネントの内部コードを最適化しました.型名でも別のコンポーネントがレンダリングされます.もう少し、我々は独自のフレームワークを持っている.
    どのようにクールですか?余りにも.
    私は、それがこれのように何かに変わることを望みます:
    const FIELDS = {
        name: getInputConfig({ visible: true, disabled: true, label: 'Model'}),
        color: getDropDownConfig({ visible: true, disabled: false}),
        size: getBlockConfig({ visible: true }),
        height: getInputNumberConfig({ visible: true }),
        width: getInputNumberConfig({ disabled: false }),
    }
    <Component
      values={values}
      fields={FIELDS}
    />
    

    Anyway, you get the idea. Do not invent your custom code design



    コンポーネントとサブフォームを合成することによる新しい形式
    我々が何を書いているかについて覚えましょう.我々はすでに反応ライブラリがあります.新しいコンストラクタを発明する必要はありません.反応のコンポーネントの構成は、JSX構文で説明されます.
    const Form1 = ({ values }) => {
      return <FormPanel>
        <FormField disabled label=Model>
          <Input name="name" />
        </FormField>
        <FormField disabled label=Color>
          <DropDown name="color" />
        </FormField>
        <FormPanel>
          <FormField disabled label="Height">
            <Input.Number name="height" />
          </FormField>
          <FormField disabled label="Width">
            <Input.Number name="width" />
         </From Field>
        </FormPanelt>
      </FormPanel>
    }
    
    我々はコピーで最初のオプションに戻っているようです.しかし、実際には我々はいません.これは最初の2つのアプローチの問題を取り除く構成です.
    フォームが組み立てられるレンガのセットがあります.各レンガは何か特別な責任があります.レイアウトや外観を担当するものもあり、データ入力を担当するものもある.
    プロジェクト全体でインデントを変更する必要がある場合は、FormFieldコンポーネントでこれを行うことができます.ドロップダウンリストの作業を変更する必要がある場合は、コンポーネントドロップダウンの1つの場所で実行できます.
    あなたが同じような形を必要とするならば、例えば、フィールド「色」がないように、別のレンガで共通のブロックを持って、もう一つの形を構築してください.
    サイズブロックを別のコンポーネントに配置します
    const Size = () =>  <FormPanel>
        <FormField disabled label="Height">
          <Input.Number name="height" />
        </FormField>
        <FormField disabled label=Width>
          <Input.Number name="width" />
       </From Field>
      </FormPanel>
    
    色の選択でフォームを作成します.
    const Form1 = () => <FormPanel>
        <FormField disabled label="Color">
          <DropDown name="color" />
       </FormField>
        <FormField disabled label="Model">
           <Input name="name" />
        </FormField>
        <Size name="size" />
    </FormPanel>
    
    次に、色の選択なしで同様のフォームを作成します.
    const Form2 = () => <FormPanel>
        <FormField disabled label="Model">
           <Input name="name" />
        </FormField>
        <Size name="size" />
    </FormPanel>
    
    最も重要なことに、このコードを取得する人は、前任者の発明されたコンフィギュレーションに対処する必要はありません.すべてのJSX、任意の反応開発者に精通して、各コンポーネントのパラメータのヒントで書かれています.

    In general, you get the idea. Use JSX and component composition.



    州についての2、3の語
    今、我々の注意を州に向けましょう.より正確に彼の不在.状態を追加すると、データフローをロックし、コンポーネントを再利用するのが難しくなります.すべてのレンガはステートレス(すなわち状態なし)であるべきです.そして、最も高いレベルだけで、レンガから組み立てられるフォームは、スタックに接続されることができます.フォームが複雑であるならば、それは複数のコンテナにそれを分割して、各部分をreduxに接続するのにすでに意味をなします.
    フォームの別のコンポーネントを作るのは怠惰ではありません.その後、別のフォームの一部として使用したり、その上にstatefull形式をビルドしたり、Reduxに接続するコンテナーを使用できます.
    もちろん、レンガは、一般的なデータフローに関連していない内部状態のストレージを持つことができます.たとえば、ドロップダウンの内部状態は展開されたかどうかのフラグを格納するのに便利です.

    All in all, you get the idea. Separate the components into Stateless and Statefull



    合計
    驚くべきことに、私は記事で説明されたすべてのエラーとそれらから生じる問題に定期的に遭遇します.私はあなたがそれらを繰り返していないし、あなたのコードのサポートをはるかに簡単になることを願っています.
    主なポイントを繰り返します.
  • 同様のコンポーネントをコピーしないでください.乾燥の原則を使用します.
  • は、多くのプロパティと機能を持つコンポーネントを作成しないでください.各々のコンポーネントは、何か異なる(固体からの単一の責任)
  • に対して責任がなければなりません
  • コンポーネントをステートレスとステートフルに分離します.
  • 独自のコード構造を作成しないでください.JSXとコンポーネントの構成を使用します.
  • 実際には、それは読者がより良い考えを理解することができるように、準備の記事だった.結局のところ、主な質問は未回答です.つのレンガからもう一つへデータを移す方法?次はこのことを読みなさい.