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

У меня возникли проблемы с интеграцией модуля response-system-notification в мое приложение, если я прочитал документацию о 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>
    )
};

person user465374    schedule 28.12.2017    source источник


Ответы (2)


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

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

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

person glennsl    schedule 28.12.2017

После некоторого дальнейшего расследования, благодаря подсказке glensl и некоторым сообщениям, которыми обменивались на 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";

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

модуль ReactNotificationSystem = {[@ bs.module] внешний reactClass: ReasonReact.reactClass = "response-notification-system / 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 здесь:

person user465374    schedule 29.12.2017