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

feat: implement global decorator config #30

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

taehee-sp
Copy link

issue #28

I implemented global decorator support for portfolio.

here is current config api (can be changed)

(defonce app
  (ui/start!
	@@ -31,6 +32,9 @@

    :config
    {:css-paths ["/portfolio/demo.css"]
     :decorators {:reagent    reagent-decorator
                  :reagent-18 reagent-decorator
                  :react-18   react-18-decorator}
   }))

example decorator implementation.

(defn reagent-decorator [child]
  (createElement Provider #js{:value :red}
                 (r/as-element child)))

(defn react-18-decorator [props]
  (createElement Provider #js{:value :red}
                 (.-children props)))

here is consumer example scene.

(defn decorator-consumer-component []
  (let [theme (use-theme)]
    ($ :button {:style {:background (name theme)}}
       "current theme is " (name theme))))

(defscene decorator-consumer-demo
  :title "using global decorator context"
  ($ decorator-consumer-component))

Issue

I just read decorators config from @app atom. I know it's not ideal, but it's difficult for me to understand the whole structure. Can you give me a suggestion please?

TODO

  • add decorator docs
  • react-toastify, @tanstack/query decorator example.

@cjohansen
Copy link
Owner

I agree that accessing the app atom this way isn't ideal. I don't think it's necessary to add the decorators to the app state at all, since they are not data. The decorators are more a detail of the rendering mechanics, like the individual framework-specific frameworks. So my suggestion is to go with a more code-driven solution, something like:

(require '[portfolio.reagent :as pr])

(pr/set-decorator! reagent-decorator)

This will just be a convention followed in each adapter, and can be implemented like so:

(ns portfolio.reagent
  ,,,)

(def *decorator* nil)

(defn set-decorator! [decorator]
  (set! *decorator* decorator))

Then:

;; Replace this
(let [decorator (or (:reagent (:decorators @app)) identity)] ,,,)

;; ...with
(let [decorator (or *decorator* identity)] ,,,)

A note on code-style: I see a lot of the namespace forms have been reformatted in various ways. This makes it hard to gauge what changes you've made. Some of them are reasonable enough, but I'd prefer the PR to only have the minimal changes necessary to support your feature, or at the very least separate commits for stuff like formatting. I also prefer using :as when requiring namespaces, and not using:refer, as I find it makes the code much harder follow. I've used :refer-macros sparingly for things like defscene etc, but I don't want Portfolio's internals to use :refer for regular functions.

@taehee-sp
Copy link
Author

Thank you for the comments. I understand the points.

I will change the PR as you said. (just pr/set-decorator! and use :as instead of :refer)

@taehee-sp taehee-sp marked this pull request as ready for review September 5, 2024 01:51
@taehee-sp
Copy link
Author

Thank you for your patience, I would like to let you know that PR is ready to review.

@taehee-sp
Copy link
Author

Just a friendly reminder. @cjohansen

Copy link
Owner

@cjohansen cjohansen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the very delayed response!

I like this API a lot better. It still needs to be defined for the remaining non-React adapters, but I can do that. They will probably just be function wrappers.

As I mentioned in the initial comment, there is a lot of unrelated and unnecessary changes to the code, mainly formatting and ordering. I would appreciate if you could revert these, I've highlighted the individual places where I want to keep the original formatting.

[portfolio.react-18 :refer-macros [defscene]]
["react" :as react]))
[portfolio.theme :as theme]
[portfolio.react-18 :refer-macros [defscene]]))

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please undo these unrelated changes.

(render [this]
(when (.. this -props -error)
(throw (js/Error. "BOOOOOM!")))
"Oh, nice!!"))
ctor))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code seems to have been reformatted with no real changes. Please undo it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one still needs fixing

@@ -4,7 +4,8 @@
;; For react versions 18+ use the following:
;; This is due to the new API https://www.metosin.fi/blog/reagent-towards-react-18/
(:require [portfolio.components.reagent.component :as rc]
[portfolio.reagent-18 :refer-macros [defscene]]))
[portfolio.theme :as theme]
[portfolio.reagent :refer-macros [defscene]]))

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you change the React version in use here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's maybe lsp related mistake. i will revert it.

[portfolio.theme :as theme]
[portfolio.react-18 :refer-macros [defscene]]
[rum.core :as rum] ;; If you are using an older version of react use the following:
))

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to have been reformatted with no real changes? Please undo it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i will undo it

(:require [portfolio.theme :as theme]
[portfolio.react-18 :refer-macros [defscene]]
[uix.core :refer [$ defui use-state]]
[uix.dom]))

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to have been reformatted with no real changes. Please undo it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will undo it

[portfolio.adapter :as adapter]))
[portfolio.adapter :as adapter]
[portfolio.ui.actions :as actions]))

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep the previous formatting/ordering of this form.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay!

(let [ctor (fn [])]
(let [ctor (fn [])
Decorator (or *decorator*
(.-Fragment react))]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm reading this right, this will end up defaulting to a fragment instead of a div as before? Seems like an improvement in itself 😊

react "div" #js {}
(if (o/getValueByKeys this "state" "error")
""
(:component (get-scene this)))))))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer if you stuck to the existing formatting here.

(if el
(do
(rd/render [decorator
(if (fn? component)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This let introduced a lot of diff noise, and decorator is only used once. I suggest inlining (or *decorator* identity) here:

(rd/render [(or *decorator* identity)
           (if ,,, ))

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay!

(:require [portfolio.adapter :as adapter]
[portfolio.data :as data]
[reagent.dom.client :as rdc]
[reagent.impl.template :as reagent])
(:require-macros [portfolio.reagent-18]))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep the original ordering here.

@taehee-sp taehee-sp force-pushed the feature/global-decorator-config branch from e427b55 to d3dc27f Compare November 2, 2024 10:01
@taehee-sp
Copy link
Author

it's done! please review @cjohansen :)

Copy link
Owner

@cjohansen cjohansen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, there are still some pending changes from the previous review. Fix 'em and I'll merge it 😊

(render [this]
(when (.. this -props -error)
(throw (js/Error. "BOOOOOM!")))
"Oh, nice!!"))
ctor))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one still needs fixing

($ :p "Count: " count)
($ :button {:on-click #(set-count inc)} "Increase"))))
($ :p "Count: " count)
($ :button {:on-click #(set-count inc)} "Increase"))))

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one still needs fixing

@@ -40,7 +48,7 @@

:viewport/defaults {:viewport/padding [16]
#_#_#_#_:viewport/width 390
:viewport/height 400}
:viewport/height 400}
#_#_:canvas/layout {:kind :cols
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one still needs fixing

(when-let [actions (:report-render-error (:actions (get-scene this)))]
(actions/dispatch actions nil {:action/exception error
:action/info (js->clj info)
:action/cause "React error boundary caught error"})))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all reformatting I think? Please keep the original formatting

react "div" #js {}
(if (o/getValueByKeys this "state" "error")
""
(:component (get-scene this)))))))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please maintain the existing formatting here, that will make it easier to see what's actually changing.

@taehee-sp
Copy link
Author

all done! (I checked my PR diff one by one) @cjohansen please review

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

Successfully merging this pull request may close these issues.

3 participants