我尝试编写一个React组件。对于html标题标签(h1,h2,h3等等),其中标题优先级根据我们在道具中定义的优先级动态变化。
这是我尝试做的事情。
<h{this.props.priority}>Hello</h{this.props.priority}>
预期产出:
<h1>Hello</h1>
这不起作用。有没有可行的方法呢?
答案 0 :(得分:244)
无法就地执行此操作,只需将其放入变量(with first letter capitalised)中:
const CustomTag = `h${this.props.priority}`;
<CustomTag>Hello</CustomTag>
答案 1 :(得分:26)
如果您使用的是TypeScript,则会看到这样的错误:
Type '{ children: string; }' has no properties in common with type 'IntrinsicAttributes'.ts(2559)
TypeScript不知道CustomTag
是有效的HTML标记名称,并抛出无用的错误。
要解决此问题,请将CustomTag
强制转换为keyof JSX.IntrinsicElements
!
const CustomTag = `h${this.props.priority}` as keyof JSX.IntrinsicElements;
<CustomTag>Hello</CustomTag>
答案 2 :(得分:19)
为了完整性,如果你想使用动态名称,你也可以直接调用React.createElement
而不是使用JSX:
React.createElement(`h${this.props.priority}`, null, 'Hello')
这可以避免必须创建新的变量或组件。
使用道具:
React.createElement(
`h${this.props.priority}`,
{
foo: 'bar',
},
'Hello'
)
来自docs:
创建并返回给定类型的新React元素。 type参数可以是标记名称字符串(例如
'div'
或'span'
),也可以是React组件类型(类或函数)。使用JSX编写的代码将转换为使用
React.createElement()
。如果您使用的是JSX,通常不会直接调用React.createElement()
。请参阅React Without JSX了解详情。
答案 3 :(得分:2)
在动态标题(h1,h2 ...)的情况下,组件可以返回React.createElement
(上面提到Felix),如此。
const Heading = ({level, children, ...props}) => {
return React.createElement(`h${level}`, props , children)
}
对于可组合性,道具和儿童都会被传递。
答案 4 :(得分:1)
你可以试试这个。我是这样实现的。
import { memo, ReactNode } from "react";
import cx from "classnames";
import classes from "./Title.module.scss";
export interface TitleProps {
children?: ReactNode;
className?: string;
text?: string;
variant: Sizes;
}
type Sizes = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
const Title = ({
className,
variant = "h1",
text,
children,
}: TitleProps): JSX.Element => {
const Tag = `${variant}` as keyof JSX.IntrinsicElements;
return (
<Tag
className={cx(`${classes.title} ${classes[variant]}`, {
[`${className}`]: className,
})}
>
{text || children}
</Tag>
);
};
export default memo(Title);
答案 5 :(得分:0)
所有其他答案都工作正常,但我会添加一些其他内容,因为这样做:
标题组件:
import React from 'react';
const elements = {
h1: 'h1',
h2: 'h2',
h3: 'h3',
h4: 'h4',
h5: 'h5',
h6: 'h6',
};
function Heading({ type, children, ...props }) {
return React.createElement(
elements[type] || elements.h1,
props,
children
);
}
Heading.defaultProps = {
type: 'h1',
};
export default Heading;
您可以像
一样使用它<Heading type="h1">Some Heading</Heading>
或者您可以有一个不同的抽象概念,例如,您可以定义一个大小道具,例如:
import React from 'react';
const elements = {
xl: 'h1',
lg: 'h2',
rg: 'h3',
sm: 'h4',
xs: 'h5',
xxs: 'h6',
};
function Heading({ size, children }) {
return React.createElement(
elements[size] || elements.rg,
props,
children
);
}
Heading.defaultProps = {
size: 'rg',
};
export default Heading;
您可以像
一样使用它<Heading size="sm">Some Heading</Heading>
答案 6 :(得分:0)
只想补充一点,如果它们是自定义组件,例如<Foo />
、<Bar />
。你可以这样做:
const condition = 'condition here'
const Comp = condition ? <Foo /> : <Bar />
然后在渲染函数中使用 <Comp />
,如下所示:
const render = () => <Comp prop='value' />
使用这种模式的一个常见情况是多种类型的组件共享同一个 props
。