Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

track dependencies to selectively rerender with useMemo #65

Open
alidcast opened this issue Oct 27, 2019 · 3 comments
Open

track dependencies to selectively rerender with useMemo #65

alidcast opened this issue Oct 27, 2019 · 3 comments

Comments

@alidcast
Copy link

alidcast commented Oct 27, 2019

Hey @Lokeh JS dev here, just started learning Clojure. I appreciate your work in integrating JS/react tools, and just now read your "when-is-immutability-fast" article.

Regarding your "wrapping all of our components in React.memo" comment in the article, I also thought about this when learning about macros. I like the idea of taking advantage of Clojure so that we can stop thinking about performance and focus on the UI. The concern seems to be that not every component needs this optimization - but wouldn't it be possible to track dependencies, and only apply the useMemo hook where it's necessary?

JS tools like mobx provide this rendering magic via proxies, but since macros give control over code+data this optimization could be done via react itself without having to add another dependency.

Just started learning Clojure/macros of course, so this is all high level for me still, would be great to hear your thoughts! Thanks

@lilactown
Copy link
Collaborator

The primary problem is still knowing whether the performance impact of memoizing the calculation is less than the performance impact of running the render function again.

One thing I do have on an alpha branch are some macros that will automatically detect what dependencies to add to the array we give to React's useMemo / useEffect / etc. Something like:

(use-memo
  [foo] ;; <-- normal use, passing in a vector of deps to give to React for memoizing the calculation
  (+ foo 1))

(use-memo
  :auto-deps ;; <-- tells macro to detect and add dependencies in the calculation automatically
  (+ foo 1)) ;; <-- macro will detect that `foo` is used in this and add it to the deps passed to React

Re: mobx. Mobx works similar to Reagent, and the way they are able to optimize renders is by tracking state outside of the render tree. The same thing can be done with hx, but it comes with some drawbacks. The pure React way focuses on keeping state within the render tree and aggressively annotating our components with memo when needed, I don't think hx can get around that yet.

@alidcast
Copy link
Author

alidcast commented Oct 28, 2019

I see, thanks for clarifying.

the biggest issue imo is not one-off declarations / nesting props but trying to use Context API for global state management, since all consuming components render for on any state change, regardless of whether their using the state. and it'd be great not to have to always use use-memo when consuming a context provider

maybe like the use-memo :auto-deps, there can also be a create-context utility for overcoming the above issue. react-tracked and constate are examples I've been looking at

@lilactown
Copy link
Collaborator

I've thought about this some more and I like what you're thinking about re: Context.

I think that this should still be opt-in, but can be made much more ergonomic with some syntax sugar.

What I'm currently playing with in my head is annotating expressions with metadata, which the defnc macro could then inspect and expand into a call to use-memo or use-callback. For instance:

(defnc MyComponent []
  (let [state (hooks/useContext global-state-context)
          foo (:foo state)]
    ^:memo [:div foo]))

Which would be expanded to:

(defnc MyComponent []
  (let [state (hooks/useContext global-state-context)
          foo (:foo state)]
    (hooks/useMemo
      (fn [] [:div foo])
      [foo])))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants