如何在 ReasonReact 中绑定和使用高阶组件
How to bind to and use a higher-order component in ReasonReact
假设我有一个高阶组件,类似于以下简单的定义,从 JavaScript 模块 ./hoc.js
:
导出
export const withStrong =
Component => props =>
<strong> <Component ...props/> </strong>
假设我有一些名为 HelloMessage
的组件,这块 JavaScript 的等价物是什么:
import { withStrong } from './hoc.js';
const HelloMessage = ...
const StrongMessage = withStrong(HelloMessage);
ReactDOM.render(
<StrongMessage name="Joe" />,
document.getElementById('react-app')
);
TL;DR:
这应该与请求的 JavaScript 片段完全相同:
[@bs.module ./hoc.js]
external withStrong
: React.component('props) => React.component('props)
= "withStrong";
module HelloMessage = ...
module StrongMessage = {
include HelloMessage;
let make = withStrong(make);
};
ReactDOMRe.renderToElementWithId(
<StrongMessage name="Joe" />,
"react-app"
);
还有一些 a runnable example on the Reason playground 进行了一些调整以解决没有单独的 JavaScript 文件的问题。
解释如下:
绑定
withStrong
只是一个函数。它恰好是一个接受和 returns 反应组件的函数,这有点神秘,但它们实际上只是像其他任何值一样的值。我们可以像普通函数一样绑定它。
即使像这样简单的东西也行得通
[@bs.module ./hoc.js]
external withStrong : 'a => 'a = "withStrong";
假设您始终确保传入一个组件。但它不是特别安全,因为你也可以传递任何其他东西,所以让我们尝试使用它应该使用的类型系统,限制它只接受反应组件。
ReasonReact source code 说组件的类型是 component('props)
,所以这就是我们要使用的类型。
[@bs.module ./hoc.js]
external withStrong
: React.component('props) => React.component('props)
= "withStrong";
在参数和 return 类型中使用 'props
类型变量意味着我们将它们约束为相同。也就是说,returned 组件将具有与传入组件完全相同的 props,这正是我们在这种情况下想要的。
这就是绑定本身的全部内容。我们现在可以像这样使用它:
let strongMessage = withStrong(HelloMessage.make);
很遗憾,这不支持 JSX。要按原样呈现 strongMessage
,我们必须编写类似
的内容
React.createElementVariadic(strongMessage, { "name": "Joe" }, [||]);
不太好。所以让我们解决这个问题。
JSX
<StrongMessage name="Joe" />
React.createElementVariadic(
StrongMessage.make,
StrongMessage.makeProps(~name="Joe", ()),
[||]
);
所以我们需要一个 StrongMessage
模块,它有两个功能,make
和 makeProps
,符合 React.createElementVariadic
的预期。 make
只是组件本身,所以这很简单。 makeProps
是一个函数,它接受 props 作为由 unit
终止的标记参数(因为 props 可能是可选的)和 returns 一个 js 对象。这也恰好是 [@bs.obj]
所做的,这绝不是巧合。
然后把这些放在一起,我们得到:
module StrongMessage = {
let make = withStrong(HelloMessage.make);
[@bs.obj]
external makeProps
: (~name: string, unit) => {. "name" string }
= "";
}
就是这样!耶!
附录:快捷方式
好的,所以 makeProps
函数有点烦人。幸运的是,在我们的例子中,包装组件的 props 与原始组件相同,这也是不必要的,因为 StrongMessage.makeProps
将与 HelloMessage.makeProps
相同。那我们就偷吧!现在我们有
module StrongMessage = {
let make = withStrong(HelloMessage.make);
let makeProps = HelloMessage.makeProps;
}
但我们可以做得更好!通过使用 include HelloMessage
我们可以完全删除 makeProps
(感谢@bloodyowl,通过@idkjs,为此)。
module StrongMessage = {
include HelloMessage;
let make = withStrong(make);
}
这很不错,不是吗?这是有效的,因为 include HelloMessage
将包括所有从 HelloMessage
导出的定义,例如 makeProps
,还有 make
和其他任何东西。当您以这种方式包装组件时,这可能是您想要的,但请注意它从包含的模块导入和重新导出 所有内容,以防 不是 你想要什么。
用法
最后,一旦我们有了绑定和 JSX,我们就可以像这样使用它了
ReactDOMRe.renderToElementWithId(
<StrongMessage name="Joe" />,
"react-app"
);
假设我有一个高阶组件,类似于以下简单的定义,从 JavaScript 模块 ./hoc.js
:
export const withStrong =
Component => props =>
<strong> <Component ...props/> </strong>
假设我有一些名为 HelloMessage
的组件,这块 JavaScript 的等价物是什么:
import { withStrong } from './hoc.js';
const HelloMessage = ...
const StrongMessage = withStrong(HelloMessage);
ReactDOM.render(
<StrongMessage name="Joe" />,
document.getElementById('react-app')
);
TL;DR:
这应该与请求的 JavaScript 片段完全相同:
[@bs.module ./hoc.js]
external withStrong
: React.component('props) => React.component('props)
= "withStrong";
module HelloMessage = ...
module StrongMessage = {
include HelloMessage;
let make = withStrong(make);
};
ReactDOMRe.renderToElementWithId(
<StrongMessage name="Joe" />,
"react-app"
);
还有一些 a runnable example on the Reason playground 进行了一些调整以解决没有单独的 JavaScript 文件的问题。
解释如下:
绑定
withStrong
只是一个函数。它恰好是一个接受和 returns 反应组件的函数,这有点神秘,但它们实际上只是像其他任何值一样的值。我们可以像普通函数一样绑定它。
即使像这样简单的东西也行得通
[@bs.module ./hoc.js]
external withStrong : 'a => 'a = "withStrong";
假设您始终确保传入一个组件。但它不是特别安全,因为你也可以传递任何其他东西,所以让我们尝试使用它应该使用的类型系统,限制它只接受反应组件。
ReasonReact source code 说组件的类型是 component('props)
,所以这就是我们要使用的类型。
[@bs.module ./hoc.js]
external withStrong
: React.component('props) => React.component('props)
= "withStrong";
在参数和 return 类型中使用 'props
类型变量意味着我们将它们约束为相同。也就是说,returned 组件将具有与传入组件完全相同的 props,这正是我们在这种情况下想要的。
这就是绑定本身的全部内容。我们现在可以像这样使用它:
let strongMessage = withStrong(HelloMessage.make);
很遗憾,这不支持 JSX。要按原样呈现 strongMessage
,我们必须编写类似
React.createElementVariadic(strongMessage, { "name": "Joe" }, [||]);
不太好。所以让我们解决这个问题。
JSX
<StrongMessage name="Joe" />
React.createElementVariadic(
StrongMessage.make,
StrongMessage.makeProps(~name="Joe", ()),
[||]
);
所以我们需要一个 StrongMessage
模块,它有两个功能,make
和 makeProps
,符合 React.createElementVariadic
的预期。 make
只是组件本身,所以这很简单。 makeProps
是一个函数,它接受 props 作为由 unit
终止的标记参数(因为 props 可能是可选的)和 returns 一个 js 对象。这也恰好是 [@bs.obj]
所做的,这绝不是巧合。
然后把这些放在一起,我们得到:
module StrongMessage = {
let make = withStrong(HelloMessage.make);
[@bs.obj]
external makeProps
: (~name: string, unit) => {. "name" string }
= "";
}
就是这样!耶!
附录:快捷方式
好的,所以 makeProps
函数有点烦人。幸运的是,在我们的例子中,包装组件的 props 与原始组件相同,这也是不必要的,因为 StrongMessage.makeProps
将与 HelloMessage.makeProps
相同。那我们就偷吧!现在我们有
module StrongMessage = {
let make = withStrong(HelloMessage.make);
let makeProps = HelloMessage.makeProps;
}
但我们可以做得更好!通过使用 include HelloMessage
我们可以完全删除 makeProps
(感谢@bloodyowl,通过@idkjs,为此)。
module StrongMessage = {
include HelloMessage;
let make = withStrong(make);
}
这很不错,不是吗?这是有效的,因为 include HelloMessage
将包括所有从 HelloMessage
导出的定义,例如 makeProps
,还有 make
和其他任何东西。当您以这种方式包装组件时,这可能是您想要的,但请注意它从包含的模块导入和重新导出 所有内容,以防 不是 你想要什么。
用法
最后,一旦我们有了绑定和 JSX,我们就可以像这样使用它了
ReactDOMRe.renderToElementWithId(
<StrongMessage name="Joe" />,
"react-app"
);