0

I have an ReasonReact overlay component with three states of fade. The first is visible at full opacity, the second is visible at almost entirely transparent, and the third is display none.

Is there a way to use lifecycle events to avoid polling to see if an external isOpen prop has been toggled?

I've tried dispatching an update from didReceiveProps and render (but ended up with infinite loops or major flickering in both approaches).

My current component.

type fading =
  | FadedIn
  | Intermediate
  | FadedOut;
type cycle =
  | In(fading)
  | Out(fading);

type action =
  | Cycle
  | PassTheCycle;

type state = {cycling};

let component = React.reducerComponent(__MODULE__);
let make =
    (~isOpen, ~onClick=None, children) => {
  ...component,
  didMount: ({send, onUnmount}) => {
    let interval = Js.Global.setInterval(() => PassTheCycle->send, 200);

    onUnmount(() => Js.Global.clearInterval(interval));
  },
  reducer: (action: action, state: state) => {
    let delay = (~delay=20, next) =>
      React.UpdateWithSideEffects(
        {cycling: next},
        ({send}) => Js.Global.setTimeout(() => Cycle->send, delay)->ignore,
      );

    switch (action) {
    | PassTheCycle =>
      switch (state.cycling) {
      | Out(FadedIn)
      | In(FadedOut) => React.SideEffects((({send}) => Cycle->send))
      | _ => React.NoUpdate
      }
    | Cycle =>
      switch (state.cycling) {
      | In(x) =>
        switch (x) {
        | FadedIn => React.NoUpdate
        | Intermediate => delay(~delay=200, In(FadedIn))
        | FadedOut => delay(In(Intermediate))
        }
      | Out(x) =>
        switch (x) {
        | FadedOut => React.NoUpdate
        | Intermediate => delay(~delay=200, Out(FadedOut))
        | FadedIn => delay(Out(Intermediate))
        }
      }
    };
  },
  initialState: () => {cycling: isOpen ? In(FadedIn) : Out(FadedOut)},
  willReceiveProps: ({state}) =>
    switch (isOpen, state.cycling) {
    | (false, In(x)) => {cycling: Out(x)}
    | (true, Out(x)) => {cycling: In(x)}
    | _ => state
    },
  render: ({state}) => {
    let className =
      Style.main(state.cycling);

    <div className> ...children </div>;
  },
};
wegry
  • 7,046
  • 6
  • 39
  • 59
  • What behavior are you trying to achieve? Is it that when `isOpen` is set to `true`, you want to gradually bring the component into view by first setting it to partially transparent and then completely opaque after a certain time interval? – Yakimych Jan 11 '19 at 17:19
  • @Yakimych yes, that's correct. – wegry Jan 12 '19 at 09:41

0 Answers0