Как определить компонент / привязку при использовании React ref в Reasonml?

У меня проблемы с интеграцией модуля реакции-системы-уведомлений в моем приложении, прочитав документацию по Reason React Ref. Я не уверен, почему ссылка не передается по стеку; намек был бы очень признателен.

Я продолжаю получать сообщение об ошибке ниже, я использовал этот компонент в прошлом в React, но кажется, что есть некоторые проблемы при использовании в ReasonML/React. Я подозреваю, что передается пустая ссылка, которая ломает компонент.

Тип элемента недопустим: ожидал строку (для встроенных компонентов) или класс / функцию (для составных компонентов), но получил: undefined. Вероятно, вы забыли экспортировать свой компонент из файла, в котором он определен, или вы могли смешать импорт по умолчанию и с именами.

Проверьте метод визуализации Notifications,

Переплет:

module NotificationSystem = {    
    [@bs.module "react-notification-system"] external reactClass : ReasonReact.reactClass = "default";

    let make = ( children ) => 
    ReasonReact.wrapJsForReason(
        ~reactClass, 
        ~props=Js.Obj.empty(),
        children
    )
};

Составная часть

type action =
  | AddNotification(string);

type state = {
    _notificationSystem: ref(option(ReasonReact.reactRef)),
};

let setNotificationSystemRef = (notificationRef, {ReasonReact.state: state}) => 
  state._notificationSystem := Js.toOption(notificationRef) ;

let component = ReasonReact.reducerComponent("Notifications");

let addNotification = (message, state) => {   
    switch state._notificationSystem^ {
    | None => ()
    | Some(r) => ReasonReact.refToJsObj(r)##addNotification({"message": message, "level": "success"});      
    }
};

let make = (_children) => {
    ...component,
    initialState: () => {_notificationSystem: ref(None) },
    reducer: (action, state) =>
        switch action {
            | AddNotification(message) =>  ReasonReact.SideEffects(((_) => addNotification(message, state)))
        },
    render: ({handle, reduce}) => (
        <div>
            <NotificationSystem ref=(handle(setNotificationSystemRef)) />
            <button onClick=(reduce( (_) => AddNotification("Test Notification Test"))) > (ReasonReact.stringToElement("Click")) </button> 
        </div>
    )
};

2 ответа

Решение

После дальнейшего расследования, благодаря подсказке glennsl и обмену сообщениями на Discord, я выкладываю полный ответ.

Проблема была связана со способом, которым bsb генерировал оператор "require" в выводе javascript:

[@bs.module "react-notification-system"] external reactClass : ReasonReact.reactClass = "default";

Издается как:

var ReactNotificationSystem = require("react-notification-system");

вместо

var NotificationSystem = require("react-notification-system");

Возможно, он немного хакерский, но я заставил bsb выдать правильный javascript, используя следующее утверждение:

[@bs.module ] external reactClass : ReasonReact.reactClass = "react-notification-system/dist/NotificationSystem";

Затем, внеся небольшие изменения в компонент оболочки, я смог заставить его работать со следующим кодом:

module ReactNotificationSystem = {[@ bs.module] external responseClass: ReasonReact.reactClass = "реагировать-система уведомлений /dist/NotificationSystem";

let make = ( children ) => 
ReasonReact.wrapJsForReason(
    ~reactClass, 
    ~props=Js.Obj.empty(),
    children
)
};

type action =
  | AddNotification(string);

type state = {
    _notificationSystem: ref(option(ReasonReact.reactRef)),
};

let setNotificationSystemRef = (notificationRef, {ReasonReact.state}) => 
  state._notificationSystem := Js.Nullable.to_opt(notificationRef) ;

let component = ReasonReact.reducerComponent("Notifications");

let addNotification = (message, state) => {   
    switch state._notificationSystem^ {
    | None => ()
    | Some(r) => ReasonReact.refToJsObj(r)##addNotification({"message": message, "level": "success"});      
    }
};

let make = (_children) => {
    ...component,
    initialState: () => {_notificationSystem: ref(None) },
    reducer: (action, state) =>
        switch action {
            | AddNotification(message) =>  ReasonReact.SideEffects(((_) => addNotification(message, state)))
        },
    render: ({handle, reduce}) => (
    <div>             
        <ReactNotificationSystem ref=(handle(setNotificationSystemRef)) />
        <button onClick=(reduce( (_) => AddNotification("Hello"))) > (ReasonReact.stringToElement("Click")) </button> 
    </div>
  )
};

Полный пример рабочего проекта можно найти на Github здесь:

Я думаю, что react-notification-system не распространяется как компонент es6 и поэтому не экспортируется default, Попробуйте удалить default из внешнего:

[@bs.module "react-notification-system"] external reactClass : ReasonReact.reactClass = "";

Вы должны всегда начинать с того, чтобы сначала опробовать простейшую реализацию, а затем постепенно наращивать ее, чтобы минимизировать возможные причины ошибок. Особенно, когда имеешь дело с чем-то таким же подверженным ошибкам, как граница js. В этом случае это было бы без сложной обработки ссылок. Вы, вероятно, обнаружите, что это все еще не работает из-за вышеизложенного, и что вы искали не в том месте, потому что откусили больше, чем могли прожевать.

Другие вопросы по тегам