-
Notifications
You must be signed in to change notification settings - Fork 546
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
Alternative idea to simplify reactive code #223
Comments
why we should track the vars made by |
@NickLiu635 A ref and its value are not the same thing. Depending on context you want to use one or the other. // A reactive string
let name = ref("jods")
// A function working with plain values
function length(s: string): number {
return s.length
}
// This is a non-reactive snapshot of the length of the string currently in the ref `name`
length(name.value) == 4 // notice the .value
// A function working with reactive values
function useLength(s: Ref<string>): Computed<number> {
return computed(() => s.value.length)
}
// This is a reactive computed containing the length of the reactive name variable
useLength(name) // notice the absence of .value
// Some functions will commonly be coded to accept either one
// so you can't statically analyze what you're supposed to do
// (not to mention the dynamic nature of JS in general)
function someLength(s: string | Ref<string>) {
return unref(s).length
} That's why you can't track all refs automatically. When you use
|
How would you expose raw ref object? Still via
I would argue this is NOT "JavaScript with expected semantics". In standard JavaScript, it's impossible for variable assignments to lead to side effects. It's also impossible for variable access to "track" dependencies. So the underlying semantics is different: you can't pretend you are writing "just JavaScript" - you know
Following the reasoning from above, using this in standalone JS/TS files means you are applying non-standard semantics to your entire codebase. In my opinion, this is more dangerous than My overall impression of this proposal is that while it circumvents the tooling issues, it isn't fundamentally better in terms of being "more JavaScript" on the mental front. In fact I'd argue it would be much harder to explain to beginners. |
Two options: let $name = ref("jods")
let name = auto($name) Or I settled for I excluded my initial
It is in the sense that if I tell you I might as well tell you that the variable will be reactive but that's not a concept that JS defines and for all you know I might use any strategy to actually implement that (maybe I'm gonna create a dirty-checking function that poll your local variables, Angular-style, maybe I'll just insert notify calls, Svelte-style). The important bit for users is that yes, this requires a loader and there's a bit of magic going on to make
I think your mental model will be trained from the start that it is contextually bound to I might be wrong but I don't see how anyone could get used to the idea that any JS variable is reactive when there's specifically a constraint to enable this: import and use In the end it's just a syntax that people can't invent and will be taught when starting Vue: "use a ref: label" or "use an auto.ref" call... it's pretty much the same education path.
If you think about it, that's exactly what Angular did and (partly) led to its success. This might as well be a personal call. Just as you said that nobody has to use
To be honest, "being more Javascript" is not my main driver here, the fact that it works in JS and tooling actually are. Svelte is different from Vue and has limitations when you compose complex reactive code from plain JS files.
This is arguable but I differ here. You need to explain that it is a label (some comments in PR didn't recognize it), that the assignment is an undeclared global variable but that it won't really be global, and that "ref:" is a magic label name that a tool will use to make that variable reactive. Here's how I'd explain You don't need to know more to get started, and if you know JS it's just that: a passthrough function that is automatically reactive. If we talk about explaining things to beginners, you need to take into considerations how many dislikes the |
If that is your main driver... check out https://github.com/johnsoncodehk/volar which already supports the I think the fear of "tooling is never gonna be there" can be fully refuted by the fact that @johnsoncodehk got it supported in Volar in a matter of days. Or put it in another way: at this point I think we should just remove "tooling is hard" from the arguments altogether. |
@yyx990803 My #1 frustration with the label proposal is the impossibility to use it in non-SFC files, and that remains. About Volar refs support: a quick glance at the code leads me to believe that it's not as a finished product as you make it sound. You know getting a proof of concept ready is quick, Pareto principle, etc. Tell me if I'm wrong but just from reading the code I have the following impressions:
Tooling is hard, in general. Webstorm IDE has great Typescript, and Vue, support. They'll have to replicate those efforts so that Webstorm Vue users can have access to similar features. Given the great Vue team, I'm sure there's nothing that time and effort can't solve. It doesn't mean I wouldn't love if you spent some of that energy on other things. SFC is not "standard" JS and to this day basic language features involving For example, could you tell me when I'll be able to:
|
I'll take this opportunity to point out something else about tooling: Here we intensively use Visual Studio (not Code). We have done so for years while building full-stack platforms with other frameworks such as Aurelia, Knockout. Adopting Vue has forced us to change our habits, and work with 2 different IDE at the same time; using VS Code for the front and VS for the back (far superior when it comes to .NET). |
@yyx990803 Thank you for sharing it!
Will implement it. I have implemented the properties that are not used in the template in the report setup() return, and their principles are similar.
I haven't provided this feature yet (you may have seen the code, but it is not available to users), I need move time to consider a lot of the issues like you mentioned, so I will put it in the future.
Will be supported in some way, I am thinking whether ref sugar conversion tool is sufficient or not.
Yes, this tool is built entirely to solve performance problems. (See: vuejs/language-tools#17 (comment))
This tool is based on the Language Server Protocol, which can be provided to support IDEs. But now there are only a few users, and I want to temporarily avoid fragmentation. |
@jods4 I can understand some of the points raised but it seems to be shifting the point from "tooling specific to the My point is, many of the pet peeves you raised applies to SFCs in general and isn't particularly That said, I think magic-function-based ref sugar does have its benefits. I'm just concerned about using it outside of SFCs - essentially leaking non-standard semantics into all code. I wouldn't mind it being implemented in userland as a babel plugin though, since it doesn't rely on specific tooling. |
Yes, I thought the same! There's just the side-effect of community fragmentation, standardization when onboarding new team members, showing code on github, or copy-pasting from/to stackoverflow questions, etc. But in a team that really want sugar in JS file and doesn't mind using alternative tools, it's 100% doable. |
Since it's a magical function underlying to simplify unwrap |
It occured to me that the unwrap operation could just re-use the well-known I like that idea because:
@dsonet I don't think the naming I proposed is particularly good, so if Vue teams takes this further I would be happy with any name, |
some updates
Considering that this feature has little benefit for previewing
Already released to 0.15.6! |
I have a proposal that is somewhere in between #228 and this one. Returning two values should make it easier to understand conceptually, even for beginners. |
If anyone wants to play with this, I built a working prototype that you can use with Vite. It should work in If you try it and have some feedback about the idea, here's a good place to post. If the Vite plugin has bugs, open an issue in the linked repo and I'll see if I can fix it. |
The new official proposal #369 is based on the same idea, so I think this issue serves no purpose anymore and can be closed. |
Goal
Enable users to write JS code that is reactive, while remaining as "plain" as possible.
In other words: use toolchain to remove the need to manipulate refs and write
.value
.This is an alternative idea to
ref:
which was introduced in #222.As we shall see it is not an alternative to
<script setup>
, as it is totally orthogonal to that proposal.Example
Here's what the traditional Todo List would look like using this idea and the
export
idea from<script setup>
:Observe that outside of variable initializations, which uses
auto
, it's plain JS code. You can readif (newTodo == "")
and writenewTodo = ""
reactive variables normally, in factnewTodo
is typed as plain string in this code.If you're familiar with Vue 3 reactivity, also observe that it's the same initialization, except we've swapped
auto.ref
forref
andauto.computed
forcomputed
.API
This introduce a single new function called
auto
:It takes a ref and unwraps its value, except the result is still reactive.
Because
auto(ref(x))
andauto(computed(() => y))
would be very common, two shortcuts functions are provided that perform just that:auto.ref
andauto.computed
.Sometimes you need to access a ref directly, not its value. For example if you want to pass it to a function that expects reactive inputs. For this purpose,
ref()
is re-purposed and will return the initialvalue
that was passed toauto()
.Also, if you write advanced code that manipulates refs in weird ways, you can mix regular refs code with auto refs code to your heart's content, it's just javascript after all.
Implementation
Plain JS variables can't be reactive.
This all works because the code is instrumented by a JS transform that would be provided by a loader, e.g.
vue-auto-loader
. In fact, this can all be done without core Vue support.That JS loader will track variables that are initialized with
auto
calls.auto()
call is removed.let x = auto.ref(3)
becomeslet x = ref(3)
andx
is actually the ref at runtime.x
is replaced by a read or write tox.value
(except pattern 3 below).ref(x)
wherex
is a tracker auto-ref are removed and replaced byx
.Those changes are visible when debugging code without source maps. It's pretty trivial transformations and the result is idiomatic Vue code.
Using
auto()
in any place other than a variable initializer is an error that would be reported by the loader.Tooling
The original code is valid Javascript, with the correct and expected semantics.
This means that you can edit this in any IDE: Atom, Sublime, VS Code, etc, without any plugin and still get complete language support (completion, refactorings, code navigation, etc).
You can use any language: Javascript, Typescript or even Coffeescript if you like, as the loader operates on the resulting JS code.
This works in any place, including
.vue
SFC but also regular standalone JS/TS files, which is handy if you write composable functions or template-less components.The text was updated successfully, but these errors were encountered: