I am having issues integrating react-system-notification module in my app, having read the documentation about Reason React Ref I am not sure why the reference is not passed down the stack; a hint would be much appreciated.
I keep getting the error below, I have used this component in the past in React but it seems that there is some issue when used in ReasonML/React. I suspect a null reference is passed down which breaks the component.
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of
Notifications
.
Binding:
module NotificationSystem = {
[@bs.module "react-notification-system"] external reactClass : ReasonReact.reactClass = "default";
let make = ( children ) =>
ReasonReact.wrapJsForReason(
~reactClass,
~props=Js.Obj.empty(),
children
)
};
Component
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>
)
};
After some further investigation, thanks to glensl hint and some messages exchanged on Discord I am posting the complete answer.
The issue was related to way bsb generated the "require" statement in the javascript output:
[@bs.module "react-notification-system"] external reactClass : ReasonReact.reactClass = "default";
Was being emitted as:
var ReactNotificationSystem = require("react-notification-system");
instead of
var NotificationSystem = require("react-notification-system");
Mightseem a little hacky however I got bsb to emit the correct javascript was using the following statement:
[@bs.module ] external reactClass : ReasonReact.reactClass = "react-notification-system/dist/NotificationSystem";
Then with some minor tweaking to the wrapper component, I was able to get it working with the following code:
module ReactNotificationSystem = { [@bs.module ] external reactClass : ReasonReact.reactClass = "react-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>
)
};
A full sample working project can be found on Github here: