反応のコンテナ/表示パターン


我々はOrnioできれいな、読みやすいコードを愛しています.これを達成するために、我々は我々のコードをできるだけ堅牢にする新しいテクニックと方法を絶えず捜しています.
数年前、我々は燃え盛りから反応へ切り替えました.最初に反応する奇妙な未知の領域のようにすべてが意味をなし何もしなかった.
質問が飛び出し始めた.コンポーネントを作る最良の方法は何ですか?いつ作るべきかそれらを可能な限り再利用できるように保つ方法?
答えを捜して、私はPresentationalでコンテナ構成要素のダンAbravovによってこの記事に遭遇しました.それを読んだ後、私は即座にそれが表されたアイデアと恋に落ちた.

では、コンテナ/ビューのパターンは何ですか?


コンテナ/ビューのパターン(また、presenttional/コンテナ、厚肉/薄型、スマート/ダムとして知られている)は、データのプレゼンテーションに責任があるすべてのステートフルなロジックとデータの取得と';ビュー';に責任がある';コンテナ';にコンポーネントを分割するテクニックです.
使用される右このパターンは、反応アプリケーションで巨大なスケーリングオプションを可能にします.我々は欲しいだけ多くの再利用することができます任意のロジックのビューを清潔に保つこと.しかし、現在、すべてのロジックがコンテナの中に含まれているので、より速くてより簡単なデバッグを許します.
このパターンを実装する簡単な例を次に示します.
Viewコンポーネントを作成します.私たちの場合では、プロファイルの画像、名前、場所、性別、ユーザーの電子メールを示す簡単なユーザーカードになります.
import style from "./Card.module.css";

const Card = ({ title, location, email, gender, image }) => (
  <section className={style.card}>
    <img
      className={style.cardImage}
      src={image}
      alt={title}
    />
    <div className={style.cardContent}>
      <h3 className={style.cardTitle}>{title}</h3>
      <span className={style.cardLocation}>{location}</span>
      <div className={style.cardContact}>
        <span className={style.cardMail}>{`email: ${email}`}</span>
        <span className={style.cardGender}>{`gender: ${gender}`}</span>
      </div>
    </div>
  </section>
);

export default Card;
今、それをきれいにするために若干のスタイルを加えましょう.
.card {
  display: flex;
  align-self: center;
  width: fit-content;
  background: #ffffff;
  box-shadow: 0px 2px 4px rgba(119, 140, 163, 0.06),
    0px 4px 6px rgba(119, 140, 163, 0.1);
  border-radius: 8px;
  padding: 24px;
  margin: 0 auto;
}

.cardImage {
  height: 80px;
  width: 80px;
  border-radius: 100px;
}

.cardContent {
  font-family: sans-serif;
  line-height: 0;
  margin-left: 20px;
}

.cardContact {
  display: flex;
  flex-direction: column;
}

.cardTitle {
  font-size: 20px;
  color: #112340;
  margin-bottom: 20px;
}

.cardLocation {
  font-size: 12px;
  color: #112340;
  margin-bottom: 22px;
  opacity: 0.85;
}

.cardMail,
.cardGender {
  font-size: 12px;
  color: #112340;
  margin-top: 15px;
  opacity: 0.65;
}
Voila私たちのカードが完了し、使用する準備が整いました.

ここで魔法が起こるところです.CardContainerという新しいコンポーネントを作成します.このコンポーネントの内部にロジックが発生します.我々は、ランダムなユーザーAPIからユーザーを取得し、我々のカードにデータを表示します.
import { useState, useEffect } from "react";

import axios from "axios";

import Card from "@components/Card";

const CardContainer = () => {
  const [userData, setUserData] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      const result = await axios("https://randomuser.me/api/");
      const user = result.data.results[0];
      setUserData({
        gender: user.gender,
        email: user.email,
        location: `${user.location.city}, ${user.location.country}`,
        title: `${user.name.title}. ${user.name.first} ${user.name.last}`,
        image: user.picture.thumbnail,
      });
    };

    fetchData();
  }, []);

  return (
    <Card
      title={userData?.title || "N/A"}
      location={userData?.location || "N/A"}
      email={userData?.email || "N/A"}
      gender={userData?.gender || "N/A"}
      image={userData?.image || ""}
    />
  );
};

export default CardContainer;
コンテナー内のすべてのロジックを分離することによって確認できるように、ビューコンポーネントはクリーンで準備ができています.

反応のフックの導入


私たちがダンのブログからフックの導入で見ることができるように、このようなコンポーネントをパッケージ化する必要はありません.フックが私たちに彼らの中でロジックを分離して、それからちょうど需要の上で彼らを呼ぶのを許すので、容器の必要はゆっくり離れて消えています.
しかし、フックと同じくらい偉大で、彼らはあらゆる問題を解決しません、したがって、このアプローチがまだ広く使われている理由.
まず、コンテナロジックをuseuserdataというカスタムフックに移動しましょう.
import { useState, useEffect } from "react";

import axios from "axios";

export const useUserData = () => {
  const [userData, setUserData] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      const result = await axios("https://randomuser.me/api/");
      const user = result.data.results[0];
      setUserData({
        gender: user.gender,
        email: user.email,
        location: `${user.location.city}, ${user.location.country}`,
        title: `${user.name.title}. ${user.name.first} ${user.name.last}`,
        image: user.picture.thumbnail,
      });
    };

    fetchData();
  }, []);

  return {
    gender: userData?.gender || "N/A",
    email: userData?.email || "N/A",
    location: userData?.location || "N/A",
    title: userData?.title || "N/A",
    image: userData?.image || "",
  };
};
ルックス良い権利.今、我々のロジックは、コンテナの代わりにフックの内側です.
でもどうやってミックスするの?
よく、我々は包装紙を作ることを試みることができます.
それをしましょう.
import { useUserData } from '@hooks/useUserData';

import Card from "@componets/Card";

const UserCardContainer = () => {
  const {
    title,
    location,
    email,
    gender,
    image,
  } = useUserData();

  return (
    <Card
      title={title}
      location={location}
      email={email}
      gender={gender}
      image={image}
    />
  );
};

export default UserCardContainer;
今ちょうど別の容器ではないですか?これは、現在のURロジックが3つの異なるファイルで分離される新しい任意の除算を作成します.
私にとって、これは本当に色っぽい方法でした、そして、それはちょうど私が望んでいたほどきれいでありませんでした.
私はフックのアイデアとコンテナ/ビューのパターンのアイデアを愛していたので、まだあきらめる準備ができていませんでした.
インターネットに!
いくつかの採掘後、私は反応フックと呼ばれるライブラリの形式で解決策を発見した.
このライブラリが私たちがすることができることは、コンテナの必要を取り除いている我々のカスタムフックで我々の見解を構成することです.
UseUserDataフックとカードコンポーネントを作りましょう.
import composeHooks from "react-hooks-compose";
import { useUserData } from "@hooks/useUserData";
import Card from "@components/Card";
import CardContainer from "@containers/CardContainer"

// composing card with our hook
const ComposedCard = composeHooks({ useUserData })(Card);

const App = () => {
  return (
    <div className="app">
      <ComposedCard />
      <CardContainer />
    </div>
  );
};

export default App;
ついに成功🎉 🎉
個人的には、どんな形や形でのコンテナ/ビューのパターンは、懸念を分離し、可能な限り再利用できるようにコードを維持する素晴らしい方法です.
私たちはOrnioでこのアプローチを愛し、それがより速くスケールするのを助けたので、それを使用し続けます、そして、それはとても簡単に構成要素を造って、テストしました.
あなたが役に立つこの記事を見つけてください.
リンク
Dan's original post
react-hooks-compose
code