Open barelyhuman opened 2 years ago
@orenelbaum, PR for the same, you can use a locally linked version to test the syntax, do check the test version of the code for the basic usage
From the test it looks like you only added the $mut
function.
Yeah, for now the changes is that it doesn’t change the variable name , it would change $a
to [a,setA]
for the initial declaration
the $mut
function allows passing in additional val, setter pairs that might not be from useState, the test just uses it as an example
reads are from $a[0]
and write are on $a[1]
instead of a
and setA
I need additional tests to see if the passing down of these works as expected
Diffs , yes there's no change other than the $mut
function on the written part, basically just changed the output to match with your target syntax.
also the $mut
is already typed so that solves the smallest problem for typescript that was mentioned.
moving ahead would be the handling of destructuring of props and usage of reactive values that come as parameters
Written code diff
import * as React from "react";
import {$mut} from "mute";
const createState=(x)=>[x,setterForX]
function Component() {
let $a = 1;
- let $b = createState(1) //couldn't even do this cause the plugin would create `useState(createState(1))`
+ let $b = $mut(createState(1));
const onPress = () => {
$a+=1
$b+=1
};
return <>
<p>{$a}</p>
<p>{$b}</p>
</>
}
Compiled code diff
import * as React from "react";
function Component() {
- const [a, setA] = React.useState(1);
+ const $a = React.useState(1);
- const [b, setB] = React.useState(createState(1));
+ const $b = createState(1);
const onPress = () => {
- setA(a + 1);
+ $a[1]($a[0] + 1);
- setB(b + 1);
$b[1]($b[0] + 1);
};
return <>
- <p>{a}</p>
+ <p>{$a[0]}</p>
- <p>{b}</p>
+ <p>{$b[0]}</p>
</>
}
It's really awesome that you are working on this. In general it's awesome that you're working on this plugin, but it's not the first plugin to introduce Svelte-like syntax to JSX. But usually with those Svelte like syntaxes, including Svelte (I think), you either can't pass those mutable state variables around or it's more verbose so it misses the point a little bit. I feel like those solutions encourage you to create all of your actions in the same component where you created the state and pass those actions around instead. The only solution I've seen where I feel like it makes sense to pass mutable state variables around is Marko, that's why I think that it's awesome that you're open to exploring how to make it work.
Kinda made it work , not sure if it's close to the syntax you were expecting but it's the latest commit in the PR and the test case is named Reactive props passed around components
and the snapshot of the same can be seen for the compiled output, i'm still trying to break it down but theoretically seems to be compiling fine
Links: Snapshot: https://github.com/barelyhuman/mute/blob/variation/array-setters/test/react/snapshots/babel.ts.md#reactive-props-passed-around-components Code: https://github.com/barelyhuman/mute/blob/8ae362ee895e222756863d1755eae18e383b1c1d/test/react/babel.ts#L44
That's awesome. It seems pretty much like what I was thinking about in the receiving end. Are you also planning to implement what I suggested in the component passing the state? e.g.
<Component $count={$a} $count2={b} $count3={$c}/>
instead of
<Component $count={$mut($a)} $count2={$mut($b)} $count3={$mut($c)}/>
I'm still not 100% sure about this but I couldn't think about any significant disadvantages yet except for the fact that I'm not sure what a.$b = $c
will do. I was thinking that it will compile to a.$b[1]($c[0])
, but it would be a little awkward if I'm trying to just add $c
to an existing object so I can pass it around. So maybe in this case we would want to do a.$b = mut($c)
which is also a bit awkward IMO and ideally I'd want people to have the ability to skip the $mut
function as much as possible. But if a.$b = $c
compiles to a.$b = $c
it's also a little bit awkward because it means that the $
prefix will behave differently in variables than it does in properties.
So, I need some kind of pointer/notation to know that the variable is already reactive and it's not to be messed with, that's where $mut
comes in, so while I can make
<Component $count={$a} $count2={b} $count3={$c}/>
this work, it'd be a hard added condition for react and not really a generalized solution since there can be cases where this wouldn't work.
a.$b = $c
for this to work though, I still have to add handling that if the $mut
is assigned to something then that something is to be considered a reactive variable, which isn't done yet.
But overall point,
getting rid of $mut
would require us to make assumptions in the plugin which might not sit well in all cases and we'll have to add conditionals for each case, if you check the Identifier
transform code right now it already hard check's it's parents a lot to make sure the wrong identifier isn't replaced.
Would just add extra work for us everytime a new spec is added to JS and we haven't handled it 😂
it'd be a hard added condition for react and not really a generalized solution since there can be cases where this wouldn't work. What do you mean exactly?
I don't understand all of what you just said but I'm not suggesting completely getting rid of $mut
, only supporting this syntax const a = { $b: $c }
instead const a = { $b: mut($c) }
which is kinda similar to what you already implemented with destructuring just the opposite direction and <Component $a={$b}/>
instead <Component $a={mut($b)}/>
which is pretty much the same thing just in JSX instead of JS. It can be a lot more concise if you pass mutable state around a lot, and it's not really overriding anything else you would want those syntaxes to mean. Right now it would only make sense to use this syntax if you're storing a value-setter pair as the value of a state (like useState([val, setter])
), which is a weird thing that you probably won't ever need to do.
<Component $a={$b}/> instead <Component $a={mut($b)}/>
doable just for the JSX props, yes
const a = { $b: $c } instead const a = { $b: mut($c) }
this I need to see how I'll be doing it, theoretically it's just adding it to the reactive variables array and also checking object props for reactivity instead of just variables.
Shouldn't be hard, but to cover all cases, I need apt test cases as well
this I need to see how I'll be doing it, theoretically it's just adding it to the reactive variables array and also checking object props for reactivity instead of just variables.
It doesn't necessary mean that a.$b
will be a reactive variable like $b
. I mean technically you can make it so that a.$b
acts like a normal variable and doesn't get compiled, at least until you destructure it or pass it to $mut
.
I'm still not 100% sure if it makes sense to make properties act like reactive variables as well. The only problem I see with it so far is that it adds complexity, but I feel like it's more consistent and will probably make the plugin feel more natural to use.
this I need to see how I'll be doing it, theoretically it's just adding it to the reactive variables array and also checking object props for reactivity instead of just variables.
I don't think that you have to track reactive properties, you can just assume that every prefixed property is reactive. In fact I think that you have to do that cause objects can be passed from other scopes.
track reactive properties
not really tracking, the current code maintains a set of vars that are to be reactive, they are specifically for simple identifiers and not for object props, I will just have to add it for the obj props as well , or they won't be replaced when compiled
so if I don't do it
a.$b = 1
// will not compile to
a.$b[1](1)
it specifically needs to the original variable right now, so in terms of the what I've written, I do have to add it to the array of properties I need to replace/compile
I mean technically I don't see why you can't just transform them as you go, same for normal mutable state variables. For properties you can do it per reference if you assume all prefixed properties are reactive. For variables you can do it per reference. I might be missing something cause I haven't really looked into the implementation. But either way this seems like an implementation detail so I don't know if it matters too much.
Shouldn't be hard, but to cover all cases, I need apt test cases as well
If you're talking about edge cases, I haven't really thought about them yet.
Yeah it's an implementation thing, I was thinking out loud with it.
If you're talking about edge cases, I haven't really thought about them yet.
that's okay, it's not like the library is going to have 1m downloads tomorrow, we can find them as we go
I just released babel-plugin-reactivars-solid which implements those ideas. I figured it would be relevant to mention it here.
@orenelbaum that looks nice, I got done with the JSX support that day, all that's left is the internal object props being detected as reactive, and we should have a featureset worth moving to the original plugin
Continuation of https://github.com/barelyhuman/babel-plugin-mutable-react-state/issues/5