完整 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
如果这是您需要的,请参阅 我们进行的讨论 并评论您的需求。如果需要,我们将再次讨论这个问题。