跳至主要内容

完整 HOC 示例

这是一个供您复制粘贴的 HOC 示例。如果某些部分对您来说没有意义,请前往 React HOC 文档简介,通过 TypeScript 中 React 文档的完整翻译获得详细的演练。

有时您希望有一种简单的方法来从其他地方(全局存储或提供程序)注入 props,并且不想持续传递这些 props。Context 非常适合这种情况,但 context 中的值只能在您的 render 函数中使用。HOC 将这些值作为 props 提供。

注入的 props

interface WithThemeProps {
primaryColor: string;
}

组件中的用法

目标是在组件的接口上提供 props,但在用 HOC 包装时,从组件的使用者那里减去这些 props。

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 prop 或覆盖通过 context 提供的 prop。

<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

这是一个更高级的动态高阶组件示例,它基于传入组件的 props 来确定一些参数

// 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 公开一个 ref。您可以使用 React.forwardRef<Ref, Props>(如 基础速查表中所述)进行文档说明,但我们更感兴趣的是更真实的示例。来自 @OliverJAsh 的 一个很好的实践示例(注意 - 它仍然有一些粗糙的边缘,我们需要帮助来测试和记录它)。

支持包装组件的 defaultProps

如果这是您需要的,请参阅 我们进行的讨论 并评论您的需求。如果需要,我们将再次讨论这个问题。