Need private packages and team management tools?Check out npm Teams »

re-debouncer

2.1.0 • Public • Published

re-debouncer

npm version build status license

Debouncer for Reason(React).

Installation

# yarn 
yarn add re-debouncer
# or npm 
npm install --save re-debouncer

Then add it to bsconfig.json:

"bs-dependencies"[
  "re-debouncer"
]

Usage

// Pass function you want to debounce
let fn = Debouncer.make(fn);
 
// You can configure timeout. Default is 100ms
let fn = Debouncer.make(~wait=500, fn);
 
// This call is debounced
fn();

Also, you can make debounced function calls cancelable:

let fn = Debouncer.makeCancelable(fn);
 
// Schedule invocation
fn.schedule();
 
// Cancel invocation
fn.cancel();
 
// Check if invocation is scheduled
fn.scheduled(); // => false
 
// Invoke immediately
fn.invoke();

Note that if you invoke immediately all scheduled invocations (if any) are canceled.

Example

type state = {
  input: string,
  response: option(string),
};
 
type action =
  | UpdateInput(string)
  | UpdateResponse(string)
  | ResetResponse;
 
let reducer = (state, action) =>
  switch (action) {
  | UpdateInput(value) => {...state, input: value}
  | UpdateResponse(response) => {...state, response: response->Some}
  | ResetResponse => {...state, response: None}
  };
 
let initialState = {input: "", response: None};
 
module Api = {
  let getResponse =
    Debouncer.make(((input, dispatch)) => {
      // Defined elsewhere in your code
      getResponseAsync(input, response => UpdateResponse(response)->dispatch)
    });
};
 
[@react.component]
let make = () => {
  let (state, dispatch) = reducer->React.useReducer(initialState);
 
  React.useEffect1(
    () => {
      switch (state.input) {
      | "" => ResetResponse->dispatch
      | _ as input => Api.getResponse((input, dispatch))
      };
      None;
    },
    [|state.input|],
  );
 
  <>
    <TextField
      value={state.input}
      onChange={event =>
        UpdateInput(event->ReactEvent.Form.target##value)->dispatch
      }
    />
    {switch (state.response) {
     | Some(response) => {j|Response: $(response)|j}->React.string
     | None => React.null
     }}
  </>;
};

Caveats

I need to pass multiple arguments to debounced function

Pack those in tuple:

let fn = Debouncer.make(((one, two)) => /* use `one` & `two` */);
fn(("one", "two"));

It doesn't work, function is not debounced

The result of Debouncer.make(fn) call must be bound to a variable (or a record property, a ref etc) for the later invocations. I.e. don't inline Debouncer.make(fn) calls in React.useEffect and such, this won't work since debounced function will be re-created on every re-render:

[@react.component]
let make = () => {
  let (state, dispatch) = reducer->React.useReducer(initialState);
 
  // Don't do this
  let fn = Debouncer.make(() => DoStuff(state)->dispatch);
 
  React.useEffect1(
    () => {
      state->fn;
      None;
    },
    [|state|],
  );
};

I need this function to be defined inside React component body

If you want, for whatever reason, to define debounced function in a React component body, you can use React.useRef for this. Don't use React.useMemo though because React doesn't guarantee that memoized value won't be re-evaluated at some point.

[@react.component]
let make = () => {
  let fn = React.useRef(None);
 
  let (state, dispatch) = reducer->React.useReducer(initialState);
 
  React.useEffect0(() => {
    fn->React.Ref.setCurrent(Debouncer.make(x => Action(x)->dispatch)->Some);
    None;
  });
 
  // somewhere in the body:
  switch (fn->React.Ref.current) {
  | Some(fn) => x->fn
  | None => ()
  };
};

License

MIT.

Install

npm i re-debouncer

DownloadsWeekly Downloads

2,321

Version

2.1.0

License

MIT

Unpacked Size

10.4 kB

Total Files

9

Last publish

Collaborators

  • avatar