Thoughts about Arrow after building and launching an app #39
Replies: 2 comments 1 reply
-
Incredible write up @Chaphasilor — Love the opinionated descriptions of how you chose to structure your code too. Really great stuff. #36 is probably the most obvious bug out there right now. Another known issue lurking in the code that I haven't fixed is reactive data inside 2 other reactive datas would cause unexpected results: const a = reactive({
foo: 'bar'
})
const b = reactive({ a })
const c = reactive({ a })
// "a" can only have "parent" in Arrow right now. Your suggestions:
Thanks for taking the time to write this up. It’s very insightful. Honestly it would make a pretty good dev.to article as well if you tweak it just a bit to be a little more of the "how I did x". |
Beta Was this translation helpful? Give feedback.
-
I spent the day rewriting some vanilla JS to use Arrow and want to add some additional use cases and thoughts to this thread.
Overall, I strongly prefer this general approach over raw DOM, or Backbone.js, with the constraint of "no fancy build systems." I got burned bad by some deprecations in a recent side project, so I'm very invested in the idea of a build-tool-agnostic frontend framework, without a special snowflake syntax, that I can just point You might be interested in Pinia as inspiration for state management. I see your docs are written in plain JS + Arrow, which is cool, but might make it difficult to do a lot of writing. Would you be open to using a tool purpose-built for docs, like VuePress or Material for MkDocs? |
Beta Was this translation helpful? Give feedback.
-
Hey there!
I've recently built and launched Jellyfin Rewind, a web app that offers something like "Spotify Wrapped", but for people listening to music via Jellyfin.
I've built the app entirely using ArrowJS, only used Vite as a bundler for convenience and slightly better performance.
Overall it was a very pleasant experience and I don't regret my choice at all! I just wanted to leave my thoughts here...
(I switched from using
I
to usingyou
at some point, please bear with me)Getting Started / Learning Curve
ArrowJS was really easy to pick up for me. I have a few years of experience using JavaScript, am self-taught without any bootcamps or major tutorials, but would still describe myself as someone who knows some of the intricacies of JS. I'm a big fan of using template literals wherever possible, so I felt right at home using Arrow.
When it comes to reactivity, I'm coming from a Vue background, so the concepts are mostly the same, at least when it comes to Vue 3.
Integrating Arrow into my workflow
As others have already mentioned on Reddit, I'm not a huge fan of unnecessary abbreviations (I hate this about C(++) and Rust), so I went with the aliases instead.
reactive
,watch
, andhtml
, pretty self-explanatory and fast enough to type. I don't mind that there are abbreviated versions, but I would like to see the non-abbreviated functions used in the docs, for clarity.As for using Arrow, my preferred way is using it to build single-page apps (SPAs), so I have one
<div id="app"></div>
that I bind to using a singlehtml
template. Inside that root template, I add any "static" components, like headers, footers, or overlays/pop-ups, as well as the dynamic content, using a reactive expression.Depending on my implementation, I use either an array or an object to hold the dynamic content. Depending on if I only want to "mount" a single instance or all instances.
As for reactive/dynamic data, I prefer to define a global "state" variable at the top of the file that contains all the data I'll need.
This makes it easy to use and combine data, but also makes sure that anything within the state is generally reactive and will properly update the templates.
As for components, I try to move everything into a "component" (assign the
html
-expression to a variable) that is either a) used multiple times, or b) a major logical unit. Inside the components, I tend to just use expressions, functional JavaScript, and raw HTML; I don't try to break every expression down into a variable.If I need to parametrize a component, I write a function that accepts an object that is destructured into the individual parameters, and prefix that function with
build
:You could even pass a
html
-template string as one of the parameters and use it in the component (e.g. for custom dialogs). Thinkslots
in Vue.Then I can easily use that function somewhere else:
Using booleans to control conditional rendering is pretty standard for most JS frameworks and works well with Arrow too.
Conditional rendering itself is done using simple ternary operators in a reactive context:
${() => condition ? onTrue : null}
. Of course, instead ofnull
, you could also render an alternative. If you have multiple alternatives, you could expand the arrow function's body by using curly braces and use a simpleif
-statement along with one or multiple return statements, or assign the options to an object and select the right option using the state:${() => state.options[state.selectedOption]}
. Whatever work best for the use case; you don't need to be consistent. You're programming, not competing for style points.watch
is used whenever I need side-effects. Pretty boring, not much to see here. Keep in mind there are currently some issues when modifying the state from inside a watcher; things might not re-render correctly. Depending on what you're trying to do, working around this might not be fun.Things to note
${() => expression}
) and what isn't (${expression}
). In my experience, most of the time you'll want things to be reactive when building an app. However, if you're using Arrow for something like a blog, static might be the way to go instead. When in doubt, it's probably better to trade performance for reliability and make everything reactive. Maybe a snippet could help?If you don't have a unique key, you can use a random one in order to force re-mounting of all items:
${() => <some expression containing the ID>}
). Otherwise, items might only move around if the key stays the same, but will keep their original index, which is not correct anymore.Things I would like to see
We have the
@event
for easily handling all kinds of events, but no easy way to add modifiers for this. Especially when using nested components, this could cause trouble, e.g. when you have a clickable item with another clickable button on it. Clicking the button should probably not also trigger the item's click event, but clicking anywhere else should.My solution so far is using a helper function that first modifies the event and then passes the event along:
@arrow-js/util
? :PWhile trying to workaround some of the
watch
bugs, I've had some instances where I would've loved to know once ahtml
-tagged template got mounted/re-rendered or unmounted.This would also be super useful for implementing more advanced components. Doing something on mount is relatively easy using the "builder" pattern from above, but unmounting seems much harder to me.
There have been some suggestions on Reddit about how this could be implemented: https://www.reddit.com/r/webdev/comments/10162jv/comment/j2ognqk/?context=3
refs
, just a way to identify components in the same or parent scope.I know this does technically work by using IDs and/or
document.querySelector()
, but that is always a bit verbose. Maybe, similar to the@event
handling we could get#ref
, and the tagged template function exposes the ref object as a parameter to the provided expressions? Here's a mockup:refs
a function would be easier to implement and stateless, not sure. I'm also not sure if this would be feasible for nestedhtml
-tagged templates...Okay, I think that's enough for now. Really love the library, it's almost exactly how I want it to be. Use vanilla JavaScript (concepts) wherever possible, and add some useful utilities where there it too much friction/repetition.
I'd love to see more a bit more development, mostly the bug fixes. Once #36 has been fixed, I think a beta release would be in order :)
Docs could also use some more detailed explanations, and I'd be happy to help with that. I think SolidJS does a pretty good job of explaining the edge cases, although I don't really like the docs overall. Because of the similarity between Solid and Arrow, I'd imagine some of the edge-cases to also apply to Arrow, but the documentation is probably still missing for that.
Keep up the good work!
Beta Was this translation helpful? Give feedback.
All reactions