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"
);
There'a also a runnable example на игровой площадке Reason с некоторыми адаптациями, сделанными для решения проблемы отсутствия отдельного файла JavaScript.
Объяснение следующее:
Связывание
withStrong
это просто функция. Это функция, которая принимает и возвращает компонент реакции, что немного загадочно, но на самом деле это просто значения, как и любые другие. Мы можем просто связать его как обычную функцию.
Даже что-то такое простое, как это, сработает
[@bs.module ./hoc.js]
external withStrong : 'a => 'a = "withStrong";
предполагая, что вы всегда обязательно передаете компонент. Но это не было бы особенно безопасно, так как вы можете передать ему что угодно, поэтому давайте попробуем использовать систему типов так, как она должна использоваться, ограничив ее приемом только реагирующих компонентов.
В исходном коде ReasonReact указано, что компоненты имеют тип component('props)
, так что это то, что мы будем использовать.
[@bs.module ./hoc.js]
external withStrong
: React.component('props) => React.component('props)
= "withStrong";
Использование переменной типа '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
— это функция, которая принимает реквизиты как помеченные аргументы, заканчивающиеся unit
(поскольку реквизиты могут быть необязательными) и возвращает объект js. Это также оказывается именно тем, что делает [@bs.obj]
, чего нет в как-то случайно.
Собрав это вместе, мы получим:
module StrongMessage = {
let make = withStrong(HelloMessage.make);
[@bs.obj]
external makeProps
: (~name: string, unit) => {. "name" string }
= "";
}
И это все! Ура!
Дополнение: ярлыки
Итак, функция makeProps
немного раздражает. К счастью, в нашем случае, когда реквизиты обернутого компонента такие же, как у оригинала, это также не нужно, поскольку 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"
);
person
glennsl
schedule
24.08.2019