ReactJSのコンポーネント構成

Reactで2年間働いた後、私は共有したいいくつかの経験があります。Reactをマスターし始めたばかりの場合は、この記事が、1〜5の5つのフォームから膨大なコンポーネントのセットまでプロジェクトを開発するための正しいパスを選択するのに役立つと同時に、混乱しないように役立つことを願っています。



あなたがすでにプロなら、おそらくあなたのクラッチを覚えておいてください。または、説明されている問題に対してより良い解決策を提供するかもしれません。



この記事では、コンポーネントの構成を整理する方法についての私の個人的な意見に焦点を当てます。

小さく始めましょう



いくつかの抽象的な形を考えてみましょう。フォームには多くのフィールド(約10〜15個)があることを意味しますが、目が上がらないように、例として4つのフィールドを持つフォームを取り上げます。



次のタイプのマルチレベルオブジェクトがコンポーネントの入り口に到着します。



const unit = {
  name: 'unit1',
  color: 'red',
  size: {
    width: 2,
    height: 4,
  },
}


経験の浅い開発者(reactを使用した最初の月の私のような)は、入力値が次の状態で保存される1つのコンポーネントでこれらすべてを実行します:



const Component = ({ values, onSave, onCancel }) => {
  const [ state, setState ] = useState({});

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

  return <div className="form-layout">
    <div className="form-field">
      <Input onChange={({ target: { value } }) =>
        setState((state) => ({...state, name: value }))
      }/>
    </div>
    <div className="form-field">
      <Input onChange={({ target: { value } }) =>
        setState((state) => ({...state, color: value }))
      }/>
    </div>
    <div className="size">
      <div className="form-field">
        <Input onChange={({ target: { value } }) =>
          setState((state) => ({...state, size: { width: value } }))
        }/>
      </div>
      <div className="form-field">
        <Input onChange={({ target: { value } }) =>
          setState((state) => ({...state, size: { height: value } }))
        }/>
      </div>
    </div>
    <div className="buttons">
      <Button onClick={() => onSave(state)}>Save</Button>
      <Button onClick={() => onCancel()}>Cancel</Button>
    </div>
  </div>
}


開発者がどれだけ迅速に対処したかを見て、顧客はこのフォームに基づいて、「サイズ」ブロックなしで別のフォームを作成することを提案します。



2つのオプションがあります(そして両方とも正しくありません):



  1. 最初のコンポーネントをコピーして、不足しているものを追加したり、余分なものを削除したりできます。これは通常、彼らが基礎として異なるコンポーネントを取り、その中の何かを壊すことを恐れているときに行われます。
  2. パラメータにコンポーネント設定を追加します。


3〜5のフォームの実装後にプロジェクトが完了した場合、開発者は幸運です。



しかし、通常、これはほんの始まりに過ぎず、さまざまな型の数は増え続けています。



次に、同様のものが必要ですが、「カラー」ブロックはありません。

次に、同様のものですが、新しい「説明」ブロックがあります。

次に、読み取り専用のブロックをいくつか作成します。

次に、同様のフォームを別のフォームに挿入する必要があります。一般的には、これから生じることがある悲しみです。



コピーによる新しいフォーム



もちろん、コピーアラウンドアプローチを採用する開発者は、新しいフォームをすばやく実装できます。10未満になりますが、その後は徐々に気分が落ちていきます。



特に再設計が発生した場合。「少し」の形のブロック間のくぼみを調整し、色選択コンポーネントを変更します。結局のところ、すべてを一度に予測することはできず、多くの設計ソリューションは、実装後に修正する必要があります。



「類似した形」について頻繁に言及されることに注意を払うことが重要です。結局のところ、製品は1つであり、すべての型は類似している必要があります。その結果、各フォームで同じものを作り直すという非常に面白くなく日常的な作業に対処する必要があります。ちなみに、テスターは各フォームを再確認する必要もあります。

一般的に、あなたはその考えを理解します。同様のコンポーネントをコピーしないでください。


一般化による新しい形式



開発者が2番目のパスを選択した場合、もちろん彼は馬に乗っています-あなたは思うかもしれません。数十の形状を描画できるコンポーネントはわずかです。プロジェクト全体のインデントを修正するか、「色」コンポーネントを変更します。これは、コードの2行を修正するためであり、テスターは2、3か所で再確認する必要があります。



しかし実際には、このパスは維持するのが非常に難しいコンポーネントを生み出しました。



それを使うのは難しいです、tk。多くのパラメーターは、ほとんど同じと呼ばれるものもあります。各パラメーターの原因を理解するには、内部に入る必要があります。



<Component
  isNameVisible={true}
  isNameDisabled={true}
  nameLabel="Model"
  nameType="input"
  isColorVisible={true}
  isColorDisabled={false}
  colorType={'dropdown'}
  isSizeVisible={true}
  isHeightVisible={true}
  isWidthDisabled={false}
/>


維持するのも難しいです。原則として、内部には複雑な織り交ぜ条件があり、新しい条件を追加すると他のすべてが壊れる可能性があります。コンポーネントを微調整して1つのフォームを出力すると、残りが壊れることがあります。

一般的に、あなたはその考えを理解します。コンポーネントを多くのプロパティにしないでください。
2番目のオプションの問題を解決するために、開発者は何を始めますか?正しい。実際の開発者として、彼らは複雑なコンポーネントを簡単にセットアップできるものの開発を開始します。

たとえば、fieldsパラメータを作成します(react-tableの列のように)。そして、フィールドのパラメータがそこに渡されます。表示されているフィールド、編集できないフィールド、フィールドの名前です。



コンポーネント呼び出しは次のようになります。



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}
/>


その結果、開発者は自分自身を誇りに思っています。彼はすべてのフィールドの設定を一般化し、コンポーネントの内部コードを最適化しました。フィールドごとに1つの関数が呼び出され、構成が対応するコンポーネントの小道具に変換されます。タイプの名前でも、別のコンポーネントがレンダリングされます。もう少しすると、独自のフレームワークが得られます。



涼しい?過度に。



うまくいけば、それはこれになりません:



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}
/>


一般的に、あなたはその考えを理解します。車輪を作り直さないでください。


コンポーネントとネストされた形状を合成することによる新しい形状



私たちがまだ書いていることを思い出しましょう。すでにreactライブラリがあります。新しいデザインを発明する必要はありません。reactのコンポーネント構成は、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 name="height" />
      </FormField>
      <FormField disabled label="Width">
        <Input name="width" />
     </From Field>
    </FormPanelt>
  </FormPanel>
}


最初のコピーオプションに戻ったようです。しかし、実際にはありません。これは、最初の2つのアプローチの問題を排除する構成です。



フォームを組み立てるレンガのセットがあります。それぞれのレンガは異なる何かに責任があります。レイアウトと外観用のものもあれば、データ入力用のものもあります。



プロジェクト全体のインデントを変更する必要がある場合は、FormFieldコンポーネントで変更するだけで十分です。ドロップダウンリストの作業を変更する必要がある場合、これはDropDownコンポーネントの1か所で行われます。



同様の形状が必要な場合、たとえば「色」フィールドがない場合は、共通のブロックを別々のレンガに配置し、別の形状を組み立てます。



Sizeブロックを別のコンポーネントに移動します。



const Size = () =>  <FormPanel>
    <FormField disabled label="Height">
      <Input name="height" />
    </FormField>
    <FormField disabled label=”Width”>
      <Input 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で記述されており、すべての反応開発者に馴染みがあり、各コンポーネントのパラメーターヒントが付いています。

一般的に、あなたはその考えを理解します。JSXとコンポーネント構成を使用します。


州について一言



それでは、状態に注目しましょう。より正確には、彼の不在。状態を追加するとすぐにデータフローが閉じられ、コンポーネントの再利用がより困難になります。すべてのレンガはステートレス(つまり、ステートレス)である必要があります。そして、一番上のレベルでのみ、レンガから組み立てられたフォームを状態に接続することができます。フォームが複雑な場合は、フォームを複数のコンテナーに分割し、各パーツをreduxに接続するのが理にかなっています。



別のステートレスフォームコンポーネントを作成するのに怠惰にならないでください。次に、それを別のフォームの一部として使用したり、それに基づいてステートフルフォームを作成したり、reduxに接続するためのコンテナーを作成したりする機会があります。



もちろん、一般的なデータフローに関連付けられていない内部状態を格納するための状態がブリックに存在する可能性があります。たとえば、内部状態DropDown(ドロップダウンリスト)では、属性が展開されているかどうかに関係なく、属性を保存すると便利です。

一般的に、あなたはその考えを理解します。コンポーネントをステートレスとステートフルに分けます。


合計



驚いたことに、私は定期的に記事に記載されているすべてのエラーとそれらから発生する問題に遭遇します。それらを繰り返さないでください。そうすれば、コードの保守がはるかに簡単になります。



私は要点を繰り返します:



  1. 同様のコンポーネントをコピーしないでください。DRYの原則を使用します。
  2. 多くのプロパティと機能を備えたコンポーネントを作成しないでください。各コンポーネントは、異なる何かを担当する必要があります(SOLIDからの単一の責任)
  3. コンポーネントをステートレスとステートフルに分けます。
  4. デザインを作り直さないでください。JSXとコンポーネントの構成を使用します。



All Articles