-
Notifications
You must be signed in to change notification settings - Fork 8
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
Reactive Hooks and Updates - Major Update - v9 #135
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've looked through some of the smaller files, if I get time later I want to review the bigger stuff soon.
package.json
Outdated
@@ -1,6 +1,6 @@ | |||
{ | |||
"name": "tram-one", | |||
"version": "8.1.3", | |||
"version": "9.0.0-beta.2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it okay to have the beta version in a master branch? or is the versioning managed by npm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we do the final merge, it'll be just 9.0.0
Summary
This PR is a major rewrite / refactoring of how tram-one works, making individual components capable of updating themselves when their state updates. This is a huge performance boost over the existing implementation that mimics React's methodology to re-render the entire app when state changes.
To better understand the motivation behind these changes, watch Rich Harris's talk on Rethinking Reactivity https://youtu.be/AdNJ3fydeao
Beta Release
Currently, the contents of this branch are released on npm under the beta tag, so you can test these changes by installing
tram-one@beta
. The version should be something likev9.0.0-beta.0
You can also install directly from this branch:
Codesandbox
If you want to play around with an example (based on the tutorial), you can see this code sandbox
https://codesandbox.io/s/tram-one-reactive-beta-o6x4j
You can even see in the demo above that the components only re-render when their state changes (without useMemo 😄)
Changes
Observables & Reactions
Instead of
useState
anduseGlobalState
, there are two new hooks,useObservable
anduseGlobalObservable
. These hooks give access to an observable object (created using nx-js/observer-util ) that when updated or set will trigger JUST those components using that state to update.This removes the need for
useMemo
, as components will only trigger when the state they are listening to changes.Effects are also observed, and so if state that they are dependent on changes, they will independently (from the component) re-trigger as well. This removes the need for dependencies or trigger in the
useEffect
.Components and effects are triggered / unobservered using the browser's MutationObserver, which tracks which new components are added, removed, or replaced.
Better Docstrings
Instead of having adjacent
.doc.js
files, the refactoring (mentioned below) has allowed the code to be properly annotated with jsdocs.Updated API Docs
The examples have been updated to include live StackBlitz for each function. This should be more valuable and exhaustive then the existing static examples, and better than the tutorial for giving people an idea for how to use the functions.
Node Properties
In order to properly update components individually, we are now storing properties on the mounted DOM. An individual element will have properties like
tram-tag-reaction
,tram-tag-new-effects
, andtram-tag-cleanup-effects
. These properties allow us to process the elements in the mutation observer.Remove / Revert Dependencies
Since we are updating the individual component, we are no longer dependent on
nanomorph
(or it's fork,tatermorph
).Since we are using observables, we no longer need to manage state using
hover-engine
.For some reason we still had
rlite-router
in our dependencies, but that has been extracted out touse-url-params
.Refactoring Globals
Previously all functions were wrapped in a function to take in a global. This has been refactored so that they get whatever the currently set global is from a function. This makes the code easier to read and easier to add to.
Remove Render-lock
Because we are no longer doing full sweeping renders of the app, we can remove the render-lock (a mechanism for stopping rendering loops in response to effects).
Mount mimics component rendering
Mount follows similar logic to how we create and process other components. Sadly, for reasons that I mostly understand but can't quite wrap my head around, in order for this to work the app needs to be wrapped in a surrounding element (right now a div).
Remove custom asserts / internal asserts
Some asserts wouldn't have an impact on the end user, so those have been removed. We are now using the library
type
to manage verifying types.testing-library
instead of unit tests on the functions themselves, we are writing tests that start an app and verify the DOM has the expected results. This is made possible with Testing Library, which gives access to the jsdom, and allows us (in unit tests) to query and interact with it like a headless browser. This is valuable because with code-coverage, it's easier to find dead branches, we are testing the code in a more real environment, and we don't have to mock out internals to verify functions work as expected.
Todo
getEvents
)Post-Release Todo