つのユースケースのために宣言的なAPIを犠牲にしないでください


イマジン.あなたは反応成分を設計しています、そして、それは大きくなります.あなたは宣言的な方法で必要なすべてのユースケースをエレガントに扱うことができました.でも・・・あなたのデザインに適合しない新しいシナリオを考えると、レンチはあなたの美しいAPIにスローされます.グリッドを手動で再読み込みしたり、フォームをリセットするような命令的なことをする必要があります.あなたはユースケースの90 %のための完全なAPIを持っているが、この1つの小さな要件はそれをすべて破壊している.何をしますか.
私を信じて、そこに行ったことがある.それはしばらくの間気が狂っています、しかし、私はついにかなりよくそれを解決するパターンを思いつきました.お見せしましょう.

グリッドを作りましょう
自分のデータを取得するページンググリッドコンポーネントを作成しようとしているとしましょう.これは、Go - to - Gridコンポーネントとして会社の至る所で使用される予定です.したがって、開発者が実装するのを可能な限り簡単にしたいと思います.
我々はそれをセットアップしたsource データを取得するためのpropuseEffect ページ番号が変わるとき.
function Grid({ source }) {
  const [data, setData] = useState({ values: [], count: 0 });
  const [page, setPage] = useState(1);

  // fetch data on page change
  useEffect(() => {
    getData();
  }, [page]);

  function getData() {
    // call the `source` prop to load the data
    return source(page).then((results) => {
      setData(results);
    });
  }

  return (
    // ... 
  );
}
次のように使われます:
function PersonGrid() {
  return (
    <Grid
      source={page =>
        fetch(`/api/people?page=${page}`)
          .then(res => res.json())
      }
      // ...
    />
  );
}
これは本当に簡単なユースケースに最適です.開発者はインポートする必要がありますGrid , パスするsource , そして、それはちょうど働きます.

ここにレンチが来る
その後、機能が追加されますPersonGrid ユーザーが新しい人々を追加することができます画面が、問題が発生します.The Grid フェッチを制御し、新しい人が追加されていることを知りませんので、リロードすることを知りません.我々が必要とするものは、データを扱う外部の方法です.我々がそれをしなければならないことを再評価しましょう.
私たちは、状態を動かして、それ自身のフックに論理をフェッチしますuseGrid , これはGrid コンポーネントは本当に簡単です.その唯一の仕事は現在、データをinstance プロップ
function useGrid({ source }) {  
  const [data, setData] = useState({ values: [], count: 0 });
  const [page, setPage] = useState(1);

  useEffect(() => {
    getData();
  }, [page]);

  function getData() {
    return source(page).then((results) => {
      setData(results);
    });
  }

  return {
    data,
    page
  };
}

function Grid({ instance }) {
  return (
    // ... 
  );
}
我々の中でPersonGrid コンポーネントは、フックでグリッドインスタンスを作成し、Grid .
function PersonGrid() {
  const grid = useGrid({
    source: page =>
        fetch(`/api/people?page=${page}`)
          .then(res => res.json())
  });

  return (
    <Grid
      instance={grid}
      // ...
    />
  );
}
我々のデータがそれ自身のフックで扱われて、それはまっすぐにreloadシナリオを作ります.
function useGrid({ source }) {  
  const [data, setData] = useState({ values: [], count: 0 });
  const [page, setPage] = useState(1);

  useEffect(() => {
    getData();
  }, [page]);

  function getData() {
    return source(page).then((results) => {
      setData(results);
    });
  }

  return {
    data,
    page,
    reload: getData
  };
}
今私たちは人を追加した後PersonGrid , 我々は、ちょうど電話する必要がありますgrid.reload() .

分析のAPI
ステップに戻って、シナリオに基づいてこれらの2つのアプローチを分析しましょう.
最初の反復Grid そのフェッチを内部的に扱うのは本当に使いやすい.これは、データの再読み込みシナリオに入ったときにのみ問題に実行されます.
The second iteration using the useGrid フックは、データの再読み込みシナリオを簡単に、まだ基本的なユースケースをより複雑にした.開発者は両方をインポートする必要がありますuseGrid and Grid . コンポーネントAPIの表面積の増加は、特に単純な使用例のために考慮される必要がある.
シンプルなユースケースのためのコンポーネント専用APIと、より複雑なもののフックAPIを持ちたい.

つのAPI、1つのコンポーネント
我々が戻るならばGrid コンポーネント、両方を含めることができますsource and instance 小道具
function Grid({
  source,
  instance = useGrid({ source })
}) {
  // Any optional props that need to be used in here should come through the `useGrid` hook.
  // `instance` will always exist, but the optional props may not.
  return (
    // ... 
  );
}
我々が得ている通知source プロップとして、我々はそれを作成するために使用しているuseGrid インスタンスのインスタンスinstance プロップ
このパターンでは、両方のコンポーネントのAPIを持つことができます.つの異なる用法に戻って、彼らは両方を今すぐに使用して動作しますGrid コンポーネント.
この場合、instance プロップsource プロップは必要ありません.フックにあるので).
function PersonGrid() {
  const grid = useGrid({
    source: page =>
        fetch(`/api/people?page=${page}`)
          .then(res => res.json())
  });

  return (
    <Grid
      instance={grid}
      // ...
    />
  );
}
この場合、source prop(それはフードの下でインスタンスを構築します).
function PersonGrid() {
  return (
    <Grid
      source={page =>
        fetch(`/api/people?page=${page}`)
          .then(res => res.json())
      }
      // ...
    />
  );
}

フックの規則
今すぐあなたのpitchforksを出す前に言うと“オプションをフックを呼び出すことはできません!”私の言うことを聞きなさい.それがなぜ第一に規則であるかについて考えてください.状態が同期から出ないように、フックは常に同じ順序で呼ばれなければなりません.それで、それが意味するものはフックがいつも呼ばれなければならないということです、あるいは、それは決して呼ばれることができません.
我々の新しいAPIでは、開発者が条件付きで提供しているケースは決してありませんinstance プロップそれらはいずれかを提供しますinstance propを指定します.useGrid 使用されません、あるいは、彼らはsource プロップ、意味useGrid フックは常に呼ばれます.これはフックのルールを満たすが、あなたは他の方法を見てエスリントを指示する必要があります.

概要
  • すべてのユースケースで最も単純なAPIを生成するのは難しい宣言と命令的なAPIを混合することができます
  • コンポーネントのロジックを制御し、デフォルトのプロップ値を作るためにフックを使用すると、命令と宣言のAPIが共存することができます