Skip to content

Moving memoized selectors outside of the component? #65

@TomiS

Description

@TomiS

Hey, I'm writing this mostly to ask feedback and possibly suggest a new example on the web page.

I've been slightly bothered by the fact that without something like the reselect library (for redux) it's quite easy to end up causing unwanted rerenders with reductive. (In real life - at least in my reality - the global state often needs to be manipulated into another shape before using it inside the components)

The current example on the page shows one should useCallback hook to avoid rerenders but as we know useCallback cannot live outside of a React component. So if we blindly follow the example from the current docs (below), we end up writing most of our complicated selectors inside React components that likely ends up causing some unnecessary code duplication if multiple components need to use the same selectors.

// Current example from the docs
[@react.component]
let make = (~id) => {
  let productSelector =
    React.useCallback1(
      state => state.products->Belt.List.keep(p => p.id === id),
      [|id|],
    );
  let product = AppStore.useSelector(productSelector);
  ...
};

So after a bit of experimenting, I figured that while useCallback needs to be inside the component, the callback itself could be located outside of the component, so let's try to do that with some currying magic. We end up with this:

// The reusable selector factory, could be arbitrary complex in real world
let makeProductSelector = (~id, state) => state.products->Belt.List.keep(p => p.id === id);

// React component, that now contains a minimal useCallback
[@react.component]
let make = (~id) => {
  let productSelector =
    React.useCallback1(
      makeProductSelector(~id),
      [|id|],
    );
  let product = AppStore.useSelector(productSelector);
  ...
};

So my questions are:

  • Are there any performance/other problems with this approach I'm overlooking?
  • If no, could this be abstracted even further? (I'll keep thinking about this too, but I'll also put this "challenge" here in case someone immediately figures it out :) )

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions