-
-
Notifications
You must be signed in to change notification settings - Fork 0
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
Pass state outside of component scope #5
Comments
well I was thinking about this and also why I was a little skeptical of adding the function level scope for the mutable state, I do have an idea that I can look into, I'll update with the example of the working example for this, since the passed reference would need to be followed around the app and that actually moves away from just being a babel transform. Will update the thoughts and example here as I progress |
I'm not sure if tracking mutable state around your code base is practical. It is the ideal solution but will probably be very hard to implement, and you will probably need to introduce restrictions since JS is too dynamic.
Both of those solutions can work with an approach where you treat every identifier prefixed with $ as mutable state, at least when it's an object property or function argument. This way in combinations with one of those solutions I mentioned you can easily get the value setter pair of a state and pass it around. As long as you pass it around in identifiers prefixed with $, the receiving function will be able to recognize it without cross file or even cross function analysis. This plugin is an example for a plugin that doesn't prefix variables, so it has to convert the mutable state variable (they call it ref) to a getter setter pair before transferring it and then convert it back to a mutable state variable after receiving it. This is a plugin for (SolidJS)[https://www.solidjs.com/] and not for React but the same logic holds there. Marko is an example of a framework with it's own language that does something kind of similar with a new syntax they added recently. |
I was going with a i still think the verbose would be easier on both the user and the plugin considering the amount of control the dev wishes to transfer around but yes, there's definitely cases where I'd want it to be handled by the plugin instead of me having to write the setters again |
This is what I've been able to achieve right now , I'm guessing this is what you were talking about do let me know if I'm off on the understanding function useCustomHook() {
let $x = { name: "reaper" };
const addAge = () => {
$x = {
...$x(),
age: 18,
};
};
return [...$x, addAge];
}
const Component = () => {
let [x, setX, addAge] = useCustomHook();
const updateName = () => {
setX({
...x,
name: "name",
});
};
return (
<>
{x.name}
{x.age}
<button onClick={updateName}>update</button>
<button onClick={addAge}>addAge</button>
</>
);
};
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
function useCustomHook() {
const [x, setX] = React.useState({
name: "reaper",
});
const addAge = () => {
setX({ ...x, age: 18 });
};
return [...[x, setX], addAge];
}
const Component = () => {
let [x, setX, addAge] = useCustomHook();
const updateName = () => {
setX({ ...x, name: "name" });
};
return (
<>
{x.name}
{x.age}
<button onClick={updateName}>update</button>
<button onClick={addAge}>addAge</button>
</>
);
}; Edit: Updated with a better example |
This is what I was talking about (well there was more to this idea, I also had ideas around working with those declarative variables on the receiving end as I'm going to show) but looking more into this approach I don't know if it can work with TS so I have to rethink everything now. So this is my fallback idea (have to look more into it too, maybe there's also problems there but at least I made sure this time that this basic example works without breaking TS): First approach - remove automatic state creation (this is my preferred approach): function useCustomHook() {
// Vanilla JS
let $x = useState({ name: "reaper" });
// TS
let $x = state({ name: "reaper" });
const addAge = () => {
$x = {
...$x,
age: 18,
};
};
return [ref($x), addAge];
}
const Component = () => {
let [$x, addAge] = useCustomHook();
const updateName = () => {
$x = {
...$x,
name: "name",
};
};
return (
<>
{$x.name}
{$x.age}
<button onClick={updateName}>update</button>
<button onClick={addAge}>addAge</button>
</>
);
};
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
function useCustomHook() {
let $x = useState({ name: "reaper" });
const addAge = () => {
$x[1]({
...$x[0],
age: 18,
});
};
return [$x, addAge];
}
const Component = () => {
let [$x, addAge] = useCustomHook();
const updateName = () => {
$x[1]({
...$x[0],
name: "name",
});
};
return (
<>
{$x[0].name}
{$x[0].age}
<button onClick={updateName}>update</button>
<button onClick={addAge}>addAge</button>
</>
);
}; This approach generalizes the concept of what I like to call "reactive variables" (like mutable state but can be used with any getter setter pair). When you declare a variable prefixed with The second approach will be almost the same but keeping the automatic function useCustomHook() {
let $x = { name: "reaper" };
const addAge = () => {
$x = {
...$x,
age: 18,
};
};
return [ref($x), addAge];
}
const Component = () => {
let [x, addAge] = useCustomHook();
let $x = $(x)
const updateName = () => {
$x = {
...$x,
name: "name",
};
};
return (
<>
{$x.name}
{$x.age}
<button onClick={updateName}>update</button>
<button onClick={addAge}>addAge</button>
</>
);
}; I'm using here Something that will work with both of those approaches is treating function params and object properties as reactive variables if they are prefixed with function($x) {
$x = $x + 1
}
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
function($x) {
$x[1]($x[0] + 1)
} Again I'm not sure that any of this will actually work as I'm still in the early exploration stages myself, but I did have this idea cooking in my head for a while now and I've been meaning to make my own plugin. |
I do have the example I shared working already, on the mentioned PR. |
I’ll check the TS example as well |
I also prefer the approach where you call your mutable state variables to get the value, but I don't think that it can work with TS. |
I had an idea. If you do go with the API where accessing mutable state by default gives you the value and not the reference ( |
so the current syntax should already be handling this? other than the setter , so just adding a way to reveal the setter would make sense or I could clone the On the other hand,
Problem statements right now
Feel like, both cross the scope of a babel transform plugin and reach a mini syntax compiler let's see what I can get done without having to follow around the reference and still keep it clean and easy to use |
What are you referring to when you say the current syntax? The syntax where you get the value by calling the mutable state? I missed one detail, I'll get to it in a bit, but other than this detail the Syntax I showed in my last comment doesn't need cross-file analysis. That's why I'm glad I came up with this idea, cause I've been thinking about this issue for a while and this is the nicest way I found to pass around data without cross cross-file analysis which also works with TS. It is maybe slightly more complicated but it's still relatively simple, there are two basic ideas here:
Those are the two basic ideas you need to make this work. In my example I threw in a few more things, like you can prefix function params themselves (not the properties). What I missed is that if I have a function for example I don't think that I'm doing a great job of explaining it but I think that with a proper tutorial/docs this shouldn't be really complicated to learn. Other approaches could be slightly easier to learn but they won't have as nice a syntax or won't work with TS. At least not the ones I've seen or thought about. |
The one the plugin already handles , I like the analogy, but I guess we could move it to a different plugin altogether than making this one complex, and the theory you have here checks out with the spec of the language and typescript so I would like to explore the outcome and ease of use, I'll create a clone repo of the plugin specifically to play around with this idea |
That's a good idea. I'm still very much playing around and in the brainstorming phase. I've been thinking about this problem for a long time now but I keep changing ny preffered syntax all the time. |
that explains the detailed level of information that you have about the issues/pitfalls with each syntax you can track the progress on https://github.com/barelyhuman/mute , It's a modified clone of this repo , I'll be making changes as needed |
It seems that right now there isn't a convenient way to pass mutable state outside of the component or hook, i.e. return it, pass it to a function or pass it to children.
The only way to get the setter is by creating a closure
val => myState = val
. So if I want to pass around mutable state (read and write) I need to get the setter, then I need to pass both the setter and the value around.This is a little verbose, and also wherever I pass the mutable state to I'll have to deal with two variables again (value and setter) instead of one.
I think that it could be nice if there was a better way to get the setter and pass around mutable state.
The text was updated successfully, but these errors were encountered: