Callback Listeners in ReasonML


#1

Hi @ all,

I have a question regarding the following code.
Is it possible to write this without mutating the “messageListener” variable?
If not, is there something else I can do, to optimize the code?

I basically want the “showMessage” function to be usable anywhere, to show Flash-Messages.

let messageListener = ref(None);

let setMessageListener = callback => {
  messageListener := callback;
};

let removeMessageListener = () => {
  messageListener := None;
};

let showMessage = (~options: messageOptions) => {
  let listener = messageListener^;
  switch (listener) {
  | Some(listener) => listener(options)
  | None => ()
  };
};

[@react.component]
let make = () => {
  let (messages, setMessages) = React.useState(() => []);

  React.useEffect0(() => {
    setMessageListener(
      Some(
        options => {
          let newMessage = [options];
          setMessages(currentMessages =>
            List.append(currentMessages, newMessage)
          );
          ();
        },
      ),
    );

    Some(() => removeMessageListener());
  });

  <div id="NotificationProvider">
    {List.map(
       message => {
         <Notification
           typ={message##typ}
           title={message##title}
           message={message##message}
         />
       },
       messages,
     )
     ->Array.of_list
     ->React.array}
  </div>;
};

Thank you very much for your help!
Torben


#2

messageListener is a piece of state, right? So I would put it in a component with useState and pass its value and a setter down as props to children components that need to add messages to the list.

Re: optimizing, I would actually use an array here, not a list–then you don’t have to deal with List.append which traverses the entire list, or with Array.of_list which also traverses the entire list. But you do need to be careful starting with an empty array that you annotate its type. BuckleScript’s Js.Array.push is unsound i.e. it can by default push values of different types into an empty array unless you set the array’s type beforehand.


#3

Yep…they are deeply nested at any level, so I would probably use Context for that…sounds good!
Thank you!

Okay…so I always thought, lists are “better” than arrays, but it depends on the usecase?


#4

There has been some back and forth about this. Personally I agree with Ricky Vetter (creator of the new ReasonReact) that arrays are more idiomatic since that’s what React expects https://twitter.com/rickyvetter/status/1119696093044981761?s=20