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

Update re-frame #3269

Merged
merged 15 commits into from
May 17, 2024
Merged

Update re-frame #3269

merged 15 commits into from
May 17, 2024

Conversation

aatkin
Copy link
Collaborator

@aatkin aatkin commented Mar 4, 2024

relates #3105 (front-end update)

After update (day8/re-frame#740), re-frame warns about subscriptions created outside of reactive context.

Document title did not seem to set correctly before, which should be fixed and has browser tests now.

  • updated package-lock.json to lockfileVersion 3, and package.json dependencies are pinned by exact version
  • updated re-frame from 1.2.01.4.3 and fixed several warnings "re-frame: Subscribe was called outside of a reactive context":
    • rems.dropdown: label functions that call e.g. (rems.text/text ...)
    • rems.table: subscription functions that call e.g. (rems.text/text ...) (edit: will be changed later)
    • rems.flash-message: use reagent.core/with-let instead of reagent.core/create-class, due to issues with reactive context
    • rems.atoms/document-title: use reagent.core/with-let instead of reagent.core/create-class, due to issues with reactive context
    • user focus "grab" and lazy-load-data in rems.spa are implemented using reagent.core/track!. at first this was only for focus grab which was splitted from main-content that used reagent.core/create-class, but the pattern seemed to fit hook-like helpers
  • rems main app is now rendered using rems.spa/app, that separates some setup code from page layout
  • extracted rems.theme namespace (cljs)
  • added react strict mode to development build. this has subtle effect of "double rendering", but should help catching issues earlier.

Checklist for author

Remove items that aren't applicable, check items that are done.

Reviewability

  • Link to issue

Testing

  • Complex logic is unit tested
  • Valuable features are integration / browser / acceptance tested automatically

@aatkin aatkin force-pushed the update-reframe branch 6 times, most recently from b1d700f to 2649dac Compare March 14, 2024 14:53
@aatkin aatkin force-pushed the update-reframe branch 2 times, most recently from f2ea32b to cb3798f Compare April 4, 2024 11:32
@aatkin aatkin marked this pull request as ready for review April 8, 2024 06:45
@aatkin aatkin changed the title WIP: update re-frame Update re-frame Apr 8, 2024
Copy link
Collaborator

@Macroz Macroz left a comment

Choose a reason for hiding this comment

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

Looks pretty good to me. I think we need to think a little bit if we should still decide not to do the raw reaction. Stuff just used to work and the workaround is pretty awful. There seems to be a fix to re-frame in the pipe although in danger of being forgotten.

Maybe it would make sense to do the "raw global var" instead for translations. The mechanism is very central to REMS but using it through the subscriptions is not necessary. If we want to try that, we could do everything here except using the raw reactions, and keep them as is even with the warnings.

package.json Outdated Show resolved Hide resolved
test/clj/rems/test_browser.clj Outdated Show resolved Hide resolved
src/cljs/rems/administration/create_catalogue_item.cljs Outdated Show resolved Hide resolved
Comment on lines -133 to +144
:items @(rf/subscribe [::duo-codes])
:items (vec (for [duo @(rf/subscribe [::duo-codes])
:let [shorthand (:shorthand duo)
label (localized (:label duo))]]
(assoc duo
::label (text-format :t.label/dash shorthand label))))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually, it could be nice to extract some or all of these as subscriptions. It is "further away" from this location, but it would make the dropdown declaration shorter, and perhaps be more performant.

Comment on lines +123 to +124
;; due to async loading, item label cannot be set ahead of time, but label function also cannot use subscriptions.
;; TODO: investigate solutions
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess here it would help for example, if the localizations were not from a subscription, but e.g. the global var set in the page load.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Could the backend do the localization for the search results?

src/cljs/rems/administration/catalogue_items.cljs Outdated Show resolved Hide resolved
src/cljs/rems/flash_message.cljs Show resolved Hide resolved
src/cljs/rems/spa.cljs Outdated Show resolved Hide resolved
src/cljs/rems/spa.cljs Outdated Show resolved Hide resolved
(r/with-let [tracked (mapv r/track! [lazy-load-data! grab-focus!])]

(if (config/dev-environment?)
[react-strict-mode [page]]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are there a lot of warnings? Should browser tests fail if there are any/more?

Would actually be nice to fail any browser tests with any seen warnings (or maybe ignore some difficult to fix ones).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Almost none actually, i have only seen one from komponentit.autosize/textarea for using (deprecated) react-dom/findDOMNode instead of ref. react-transition-group (not in this PR) also triggers that warning under strict mode if DOM element ref is not manually handled.

It could be good to test what warnings/how many are produced. #2368 already exists for tracking this, too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

React 18 slightly changes component mounting/unmounting in strict mode: https://react.dev/blog/2022/03/08/react-18-upgrade-guide#updates-to-strict-mode

Although this looks more related to using react/useState, which our components are not using (dropdown via react-select might be).

aatkin added 10 commits April 18, 2024 15:06
- updated package-lock.json to v3 (used by npm v9 and above, shipped with Node v20)
- pinned node dependencies with exact version
- added follow-redirects to package.json - originally security update introduced by dependabot, added here to ensure it is not accidentally wiped out during dependency update
Update to re-frame brought attention to several subscription leaks in rendering.

Document title was left untested, probably because previous implementation of document title component did not correctly set the document title. Login page and extra pages may still use different h1, but at least automatic checks are now in place.
As part of re-frame update, subscriptions should no longer be created outside of reactive context. Dropdown constantly re-renders the list of items, and label function is effectively called for each item.
As part of re-frame update, prevent subscription from being created outside of the reactive context. Lifecycle events in class components seem to be a rather common source of these bugs. Reagent has utils for working with these events in functional-y manner, but additional API could be less confusing since mount/update/unmount are more standard than with-let.
- Extract rems.spa/app from page. This allows app to separate lazy-loading/grab-focus "hooks" from page, and render additional React strict mode in dev without entangling layout
- Use functional component in rems.spa/app over React class to prevent leaking subscriptions. React class wrappers using subscription seem to be a problematic pattern in this regard
- rems.theme namespace. Not much for now, but should encapsulate some special rules like rendering logo only if navbar logo does not exist
- React helpers in util namespace. Thin wrappers, but make it slightly easier to use e.g. react-profiler
User might want to see changes reflected to current scroll position when changing language, so forcing focus does not make sense.
src/cljs/rems/theme.cljs Outdated Show resolved Hide resolved
Copy link
Collaborator

@Macroz Macroz left a comment

Choose a reason for hiding this comment

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

Ok let's get this merged and we can find any problems with manual testing.

@aatkin aatkin merged commit 2060ace into master May 17, 2024
7 checks passed
@aatkin aatkin deleted the update-reframe branch May 17, 2024 11:35
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.

2 participants