JavaScript
React
react-hooks

ReactコンポーネントのコンポジションとReact hooksのコンポジションの比較


はじめに

React hooksはコンポジションによるカスタムフックが強みです。本稿では、コンポーネントとhooksのコンポジションを比較する簡単なコードを紹介します。


Reactコンポーネントの場合

簡単な例を考えてみましょう。

const Person = ({ person }) => (

<div>
<div className="personFirstName">
<span>First Name:<span>
<span>{person.firstName}</span>
</div>
<div className="personLastName">
<span>Last Name:<span>
<span>{person.lastName}</span>
</div>
</div>
);

コンポジションにより、このコンポーネントを分割して構成するようにすると例えば次のようになります。

const FirstName = ({ name }) => (

<div className="personFirstName">
<span>First Name:<span>
<span>{name}</span>
</div>
);

const LastName = ({ name }) => (

<div className="personLastName">
<span>Last Name:<span>
<span>{name}</span>
</div>
);

const Person = ({ person }) => (

<div>
<FirstName name={person.firstName} />
<LastName name={person.lastName} />
</div>
);

なぜこのように分割するのでしょうか。再利用性のためです。例えば、この FirstName は他のコンポーネントでも使うことができます。


React hooksの場合

hooksの場合はどうなるでしょうか。例えば、 usePerson というフックがあると仮定します。これはpersonオブジェクトを返すものとします。どのように実装されるかは重要ではありませんが、例えば useContext で実装されていると考えると分かりやすいでしょう。

const Person = () => {

const person = usePerson();
const firstName = person.firstName;
const lastName = person.lastName;
return <div>{firstName}{' '}{lastName}</div>
};

これは極端に単純にしたコード例ですが、これをコンポジションによって分割構成してみましょう。

const useFirstName = () => {

const person = usePerson();
return person.firstName;
};

const useLastName = () => {

const person = usePerson();
return person.lastName;
};

const Person = () => {

const firstName = useFirstName();
const lastName = useLastName();
return <div>{firstName}{' '}{lastName}</div>;
};

雰囲気はつかめたでしょうか。このように分割することで同じように useFirstName を他のコンポーネントやhooksで再利用できるようになります。


おわりに

コンポジションは重要です。コンポーネント組み合わせて新しいコンポーネントを作れるように、hooksを組み合わせてカスタムフックを作ることができます。


おまけ

コンポーネントのコンポジションにおいては children があります。hooksにおいてこれと同等のものは何になるでしょう。もしかしたら、ファクトリーがそれに該当するかもしれません。

const createPersonHooks = (usePerson) => {

const useFirstName = () => {
const person = usePerson();
return person.firstName;
};
const useLastName = () => {
const person = usePerson();
return person.lastName;
};
return { useFirstName, useLastName };
};

これが同等のものかは確信はありません。ちなみに、constateはこのようなアプローチで作られているようです。