メインコンテンツへスキップ

フル HOC 例

これはコピーアンドペースト可能な HOC の例です。特定の部分が理解できない場合は、React HOC ドキュメントのイントロダクションに進み、TypeScript の React ドキュメントの完全な翻訳を通じて詳細なウォークスルーを入手してください。

場合によっては、他のどこか(グローバルストアまたはプロバイダー)からプロパティを挿入する簡単な方法を行いたいが、そのためにプロパティを継続的に引き継がせたくない場合があります。この場合、Context は最適ですが、Context の値は `render` 関数でのみ使用できます。HoC はこれらの値をプロパティとして提供します。

挿入されたプロパティ

interface WithThemeProps {
primaryColor: string;
}

コンポーネントでの使用法

目標は、インターフェースでプロパティをコンポーネントに利用できるようにすることですが、HoC でラップしたときにコンポーネントのコンシューマーの場合は差し引かれます。

interface Props extends WithThemeProps {
children?: React.ReactNode;
}

class MyButton extends React.Component<Props> {
public render() {
// Render an the element using the theme and other props.
}

private someInternalMethod() {
// The theme values are also available as props here.
}
}

export default withTheme(MyButton);

コンポーネントの消費

コンポーネントを使用するときは、`primaryColor` プロパティを省略したり、Context で提供されたプロパティをオーバーライドしたりできます。

<MyButton>Hello button</MyButton> // Valid
<MyButton primaryColor="#333">Hello Button</MyButton> // Also valid

HoC の宣言

実際の HoC です。

export function withTheme<T extends WithThemeProps = WithThemeProps>(
WrappedComponent: React.ComponentType<T>
) {
// Try to create a nice displayName for React Dev Tools.
const displayName =
WrappedComponent.displayName || WrappedComponent.name || "Component";

// Creating the inner component. The calculated Props type here is the where the magic happens.
const ComponentWithTheme = (props: Omit<T, keyof WithThemeProps>) => {
// Fetch the props you want to inject. This could be done with context instead.
const themeProps = useTheme();

// props comes afterwards so the can override the default ones.
return <WrappedComponent {...themeProps} {...(props as T)} />;
};

ComponentWithTheme.displayName = `withTheme(${displayName})`;

return ComponentWithTheme;
}

TS 3.2 の現在のバグのためにアサーション `{...(props as T)}` が必要であることに注意してください https://github.com/Microsoft/TypeScript/issues/28938#issuecomment-450636046

以下は、渡されるコンポーネントのプロパティの一部に基づいてパラメーターを作成する動的な高階コンポーネントの、さらに高度な例です。

// inject static values to a component so that they're always provided
export function inject<TProps, TInjectedKeys extends keyof TProps>(
Component: React.JSXElementConstructor<TProps>,
injector: Pick<TProps, TInjectedKeys>
) {
return function Injected(props: Omit<TProps, TInjectedKeys>) {
return <Component {...(props as TProps)} {...injector} />;
};
}

`forwardRef` の使用

「真の」再利用性を得るには、HOC の参照も公開することを検討する必要があります。`React.forwardRef<Ref, Props>` を 基本チートシートで説明されているように使用できますが、より現実的な例に興味があります。@OliverJAsh (注意:まだ手が加えられていない部分があり、テストやドキュメント化のためにヘルプが必要です) の 実際の良い例があります。

`defaultProps` のサポート

これが必要な場合、行いそこねた議論を参照し、要件をコメントで知らせてください。必要に応じてもう一度取り上げます。