Skip to content

Use Proxy-based selectors #1653

Closed
Closed
@theKashey

Description

@theKashey

Based on:


Proxy based solutions were floating around for a while, and actually actively used inside(MobX) and outside of React ecosystem(especially in Vue and Immer). I am opening this discussion to resolve status quo and add some momentum to Redux + Proxies investigations.

Overall proxies are capable to solve 3 objective:

  • selector memoization. Proxies can be provide more efficient memoization(comparing to reselect) in some cases, where just some pieces of state matters, as seen in proxy-memoize or redux-tracked
import memoize from 'proxy-memoize';

// reading only `.a` and `.b`
const fn = memoize(x => ({ sum: x.a + x.b, diff: x.a - x.b }));

fn({ a: 2, b: 1, c: 1 }); // ---> { sum: 3, diff: 1 }
fn({ a: 3, b: 1, c: 1 }); // ---> { sum: 4, diff: 2 }
fn({ a: 3, b: 1, c: 9 }); // ---> { sum: 4, diff: 2 } (returning old value)
//                        ^ "c" does not matter
  • testing. While the use case above is a little synthetic and such memoization is not really needed unless a developer willing not to use any memoization at all, it can be used to check selector quality, and report all selectors which react to the state change while they should not

technically running selector twice in dev mode might solve majority of the problems, like returning new array/object every time, proxy based memoization is capable to detect more complicated situations and provide some guidance around the problem. As seen in why-did-you-update
image

  • slice isolation. One named issue of redux is it's "global" store, and the fact that all listeners would be notified on state update. Knowing which slices were updated, and which selectors are listening for them, might provide an optimisation for selectors. This is actually a very old idea - Use React.createContext() with observed bits #1021 - but still valuable.

What proxies can solve:

  • speed. Proxy based memoization works "more often" and might result a better experience
  • less dev pain. Proxies "just works". At least, in the test mode, they can point on the problem instantly, not asking to invest some hours in debugging.
  • TBD

What proxies cannot solve:

  • per-component memoization. It's just absolutely orthogonal problem.
  • TBD

What proxies can break:

  • As long as one has to wrap state with a Proxy - one will use Proxy in all "frontend" code. In the same time at reducers/middleware side it will be just state. (Only once) I had a problem with "equal reference" memoization working differently in useSelector and saga. It's very edge-case-y, but having state sometimes wrapped, and sometimes not can break stuff.

Actionable items:

  • decide about proxy-memoized selector
  • decide about proxy-based selector pureness / quality checking
  • decide about slice isolation or/and proxy-based tracking/DevTools integration. It's really possible to know which components reading which slice or/and react to a some piece of information and this knowledge can transform DevTools.

cc @markerikson , @dai-shi

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions