超越 JSX
JSX 是一个语法糖,允许我们以类似 HTML 的方式组合 React 组件。要使用 JSX,组件需要遵循某些接口约定。本章节会深入 JSX 转换的细节,以及 JSX 底层使用的 React API。
注意:本章需要你了解 创建元素 的底层 API,例如 React.createElement
或 ReactDOMRe.createDOMElementVariadic
。
注意:本章假设你的 bsconfig.json
拥有 "reason": { "react-jsx": 3 }
设置,从而能够正确应用 JSX 转换。
组件类型
普通的 React 组件被定义为 ('props) => React.element
函数。
下面是一些例子,演示了如何定义组件类型(与现有 JS 代码互操作,或传递组件时很有用):
RES// Plain function type
type friendComp =
({"name": string, "online": bool}) => React.element;
// Equivalent to
// ({"padding": string, "children": React.element}) => React.element
type containerComp =
React.component<{
"padding": string,
"children": React.element
}>;
上面的类型非常底层(基本上是 React 组件的 JS 表示),ReScript React 使用更富有语言特点方式来定义 React 组件,接下来让我们详细了解。
JSX 组件接口
ReScript React 组件是一个(子)模块,含有被 JSX 使用的 make
和 makeProps
函数。为了更好的使用体验,我们提供一个 @react.component
装饰器来为你创建这些函数:
在扩展后的输出中:
makeProps
:一个接收多个标签参数(prop 名)的函数,返回一个被 make(props) 消耗的值。make
:一个转换后的make
函数,编译到组件接口(props) => React.element
。
注意: makeProps
函数总会包含一个 ~key
参数。
特殊情况 React.forwardRef
@react.component
装饰器也对 React.forwardRef
生效:
就像上面的被扩展后的输出,装饰器会转换传给 React.forwardRef
的函数,就像转换典型的组件 make
函数一样。它也会创建一个 makeProps
函数,而且会添加 ref
prop,便于我们在 JSX 调用时使用(<FancyInput ref=.../>
)。
现在,我们明白了 ReScript React 组件是如何转换的,让我们接着看看 ReScript 如何转换 JSX 结构。
JSX 底层原理
当我们在自定义组件使用 JSX 时(“首字母大写的 JSX”),我们实际上使用 React.createElement
去创建新元素。下面是没有子元素的 React 组件的例子:
如你所见,它使用 Friend.make
和 Friend.makeProps
调用 React.createElement
API。如果你提供了子元素,它会调用 React.createElementVariadic
(React.createElement
的一个不同绑定):
注意,~children=React.null
属性没有意义,因为 React 只关心传递给第三个参数的子元素数组。
DOM 元素
“首字母未大写的 JSX” 表达式会被视为 DOM 元素,并被转换为 ReactDOMRe.createDOMElementVariadic
调用:
有子元素的 JSX 也一样: