先来一小段代码
const Demo = <div>Demo</div>
const App = () => {
return (
<div>
<Demo></Demo>
</div>
);
}
不知道这段代码大家会不会发现是错误的,这里的Demo
是一个JSX
,并不是一个组件,所有不能使用
这种方式内嵌到其他组件中,正确的方式应该是
const Demo = <div>Demo</div>
const App = () => {
return (
<div>
{ Demo }
</div>
);
}
再来看一个例子
const Demo = ({children}) => <div>{children}</div>
const App = () => {
return (
<div>
<Demo>Demo</Demo>
</div>
);
}
这里的const Demo = ({children}) =>
中的children
也是渲染一个JSX
,所以使用花括号的方式渲染
,也就是{children}
。
总结一下
如果是JSX,使用花括号的方式渲染
如果是组件,使用尖括号包裹渲染
我们再来看一下组件类型。
其实React中描述组件类型有很多方式,刚开始的时候还是很容易迷惑的。例如:
import React, { ComponentType, FunctionComponent } from "react"
const App:React.FC<any> = () => {
return (
<div>
Demo
</div>
);
}
const App:ComponentType<any> = () => {
return (
<div>
Demo
</div>
);
}
const App:FunctionComponent<any> = () => {
return (
<div>
Demo
</div>
);
}
const App:() => JSX.Element = () => {
return (
<div>
Demo
</div>
);
}
方面这几种定义组件的方式都不会报错。并且都是正确的方式,我们平时大概都用React.FC
。
其实这几种方式都有很强的关系,不是超集,就是子集。我们把他们的定义找到,来看一下:
React.FC
type FC<P = {}> = FunctionComponent<P>;
ComponentType
type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
FunctionComponent
interface FunctionComponent<P = {}> {
(props: P, context?: any): ReactNode;
propTypes?: WeakValidationMap<P> | undefined;
contextTypes?: ValidationMap<any> | undefined;
defaultProps?: Partial<P> | undefined;
displayName?: string | undefined;
}
JSX
declare global {
/**
* @deprecated Use `React.JSX` instead of the global `JSX` namespace.
*/
namespace JSX {
interface Element extends React.ReactElement<any, any> {}
// .....
// 这里省略一些其他类型
}
interface ReactElement<
P = any,
T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>,
> {
type: T;
props: P;
key: string | null;
}
ReactNode
type ReactNode =
| ReactElement
| string
| number
| Iterable<ReactNode>
| ReactPortal
| boolean
| null
| undefined
| DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES[
keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_EXPERIMENTAL_REACT_NODES
];
这里可以发现React.FC
其实就是FunctionComponent
,ComponentType
是ComponentClass
和FunctionComponent
的集合,而FunctionComponent
的函数表达类型是 (props: P, context?: any): ReactNode;
,然后ReactNode
是一个联合类型,其中的一个类型就是ReactElement
分析到这里,我们再来看一下JSX.Element
,JSX.Element
继承至React.ReactElement
。
所以到这里,这4个类型都有所关联,这里有一些绕。这里只是想说,如果以后看到这些类型,希望能不会那么困惑。
还有一个小注意点,类似于vue的插槽吧,来看一个demo
import { ComponentType, FunctionComponent, ReactNode } from "react"
type DemoProps = {
children: ReactNode
}
const Demo: React.FC<DemoProps> = ({children}) => <div>{children}</div>
const App = () => {
return (
<div>
<Demo>Demo</Demo>
</div>
);
}
这里我们声明组件Demo
的children
类型是ReactNode
,或者你定义成JSX.Element
类型也可以,不过需要注意的是JSX.Element
类型的范围更小。