DEV Community

Cover image for Javascript Proxy Magic: How I built a 2kB state manager with zero dependencies (and how it got me two different job offers)
Lev N.
Lev N.

Posted on • Edited on • Originally published at hackfm.com

Javascript Proxy Magic: How I built a 2kB state manager with zero dependencies (and how it got me two different job offers)

What is a state manager exactly? A state manager is a smart module that is capable of retaining session data (of an application or web application) and reacting to changes in the data.

Are you a web developer? Ever used libraries such as Redux, Mobx or Zustand? Congratulations! You have used a state manager.

I remember my first days trying to set up (the old) Redux for React. I get PTSD just thinking about all the unnecessary complications - dispatchers, reducers, middleware! I just wanted to declare some variables, please make it stop.

It was an over-engineered, bloated library that EVERYBODY used! And for some crazy, unknown reason, it was the industry standard back then.

Some backstory

One night back in 2021 when I could not fall asleep, I aimlessly opened GitHub and noticed my old college course teacher (which I followed on GH) uploaded an assignment for his current students. The assignment required the students to create a Pokedex website using a public Pokemon API. The goal was to implement it in Javascript (without frameworks or libraries because his current students were web-dev beginners who were still learning the basics of Javascript and development).

As a joke, and mainly because I couldn't sleep, I started working on my Pokemon website. Eventually, I was able to create something viable, without using any external libraries.

But along the way, I struggled...

You see, I was so used to having a state manager, that the requirement of building even a simple, two-page application without using external frameworks or libraries got me thinking - Why do state managers have to be so complicated? It's just variables and events.

Long story short, I found myself hacking together a super-simple state manager module at 2 AM, just to manage the state of my Pokemon web app. I deployed my site to GitHub pages and forgot all about it.

A few months went by, but for some reason, I kept thinking about my state management solution now and then... You see, it had something other libraries didn't have - IT WAS BRAIN DEAD SIMPLE.

"Hey!" I thought to myself, "I should rewrite it as an NPM package".

That same night, I did exactly that - I wrote it as an independent NPM package. At the end of it all, it weighed 2kB (compared to Redux's 150kB), had zero dependencies and was so dead simple to use, that you could have set it up in just 3 lines of code.

I called it VSSM

Stands for Very Small State Manager.

You can check out the source code on GitHub. Also, take a look at the documentation site that is built with React and VSSM.

The following day, I published my NPM package, and once again forgot all about it.

Later that same year, I interviewed in two different companies for a full-stack developer role. I aced the interviews of the first company, which was a very established tech company. As a part of the interview process, they asked me to tell them about whether I code in my free time or if there are any open source projects I contributed to and so on.

The only cool thing I did back then was VSSM, so I told them about it. They were impressed with the idea that I built a "Redux alternative" all on my own.

On the other hand, I failed miserably in the second company's interview. I had blackouts, I was nervous and could not answer simple questions such as

"Does React re-render the entire application upon state changes, or does it only update the affected components and their children when using Redux?"

"It re-renders the whole app every time the state is updated", I said.

I was very nervous, haha, obviously I knew the correct answer was "It only renders the registered components and possibly their affected children".

To this day I have no idea why company No. 2 decided to give me a second chance. They invited me over for another interview (YES!).

During my second interview, they asked me to tell them about whether I code in my free time, open source contributions, you know the drill. The interviewer looked very pleased when I told him about my little side project, it seemed he liked me just for the fact that I coded a state manager from scratch.

I guess that was the case because I also failed the second interview (ran out of time during the coding challenge) but still got an offer. Company No. 1 intended to send me an offer but I had already signed my offer with Company No. 2.

My bottom line is - the fact I built VSSM helped me get both offers.

How did I do it?

Did you know that Javascript has all the functionality needed to monitor variable changes already built in?

It's called a Proxy (and it's magic).

A Javascript proxy is an additional layer of logic between the code and the assignment of variables.

If you were to wrap an object in a proxy, you could decide to log its values to the console every time it is updated, without doing anything but assigning a new value to the object.



const target = {
  v: "hello"
}

const proxyTarget = new Proxy(target, {
  set: (target, property, value) => {

      console.log(`${property} is now ${value}`); 

    target[property] = value;
    return target[property];
  }
});

proxyTarget.v = "world!" // v is now world!



Enter fullscreen mode Exit fullscreen mode

VSSM is built on proxies, it creates a layer between variable assignment and the rest of the code. Using a Proxy, you can set setters, getters and implement any sort of logic whenever the value of the target is manipulated or requested.

VSSM is a bit more than just a proxy, it's an assortment of intelligent proxies that know whether the value you assigned to the variable is its new value or a callback method.

For example, using VSSM you can set a state, listen to changes and emit an event with just a few lines of code.



import { createVSSM, createState } from 'vssm';
import { getVSSM } from 'vssm';

// Create the initial state
createVSSM({
  user: createState('user', {
    address: ''
  })
});

// Get the user proxy reference
const { user } = getVSSM();

// Listen to events on user.address
user.address = () => {
    console.log(`Address updated! the new address is ${user.address}`);
};

// Emit the mutation event
user.address = 'P.Sherman 42 Wallaby Way, Sydney'



Enter fullscreen mode Exit fullscreen mode

As you can see, I made sure my state manager was as simple as they could be. My goal was to get rid of having to wrap your head around reducers, middlewares and extremely complicated configurations just to assign some variables.

Now, everything works by assigning variables! Want to set up a listener? Assign a callback function to the variable. Want to edit the value and emit an event? Just assign a new value.

To this day I don't understand why popular state managers have to be so complex, maybe I never will.

I encourage you to go ahead and read all about Javascript Proxies on MDN Web Docs.

What is the conclusion of all of this?

Passion for what you do is key, I think.

I built VSSM just to push my limits and publish a reasonable NPM package. It managed to impress interviewers and peers and got me into different positions ever since.

Nobody will ever use VSSM, it will not be popular. I was aware of this fact when I published it to NPM. Yet I still chose to do it to the best of my abilities, because I had a passion for doing something that I conceive is better than the industry standard. I knew I could make something that had to be better, even if it meant it was just better for me.

Even though VSSM is laying dead in the NPM graveyard, it brought me a lot of value and is continuing to do so because of this article.

The best way to get a development job is to build amazing things, even if you think it all has been done before - build it better. Even if you think no one will ever use it, what is the point? - Build it now, value will come later.

Do not underestimate your abilities, if you believe they are lacking, know that you will improve. Go out there and build projects that bring value, one small step at a time.

Good luck on your engineering journey.

Top comments (62)

Collapse
 
sultan99 profile image
Sultan • Edited

I did a similar library.
Image description

import {createState} from '@holycow/state'

// 👇 your store is a hook!
const useUser = createState({
  id: 1,
  name: 'Homer Simpson',
  address: {
    house: 742,
    street: 'Evergreen Terrace',
  },
})

const UserName = () => {
  const {name} = useUser() // 👈 value from the state
  return <div>{name}</div>
}

const {id, name, address} = useUser 
// any values 👆 from the hook can be used outside of components
Enter fullscreen mode Exit fullscreen mode
Collapse
 
lnahrf profile image
Lev N.

Looks great! Did you also use Proxies?

Collapse
 
sultan99 profile image
Sultan

Yes, I used proxy too.

Collapse
 
mfp22 profile image
Mike Pearson

MVC doesn't scale. Redux has boilerplate, but it scales.

Collapse
 
lnahrf profile image
Lev N.

I never said this should replace Redux :) I also don't know if this scales, but complexity wise Redux doesn't have to scale, it's extremely complicated from the get-go.
There is beauty in simplicity.

Collapse
 
mfp22 profile image
Mike Pearson

Come on. Complexity isn't binary. Let's say Redux is 3 out of 10 complex. This solution is 1 out of 10 complex for simple apps. Redux will grow to 5 out of 10 complex maximum, well this will grow to 10 out of 10 complex.

And when you say this doesn't replace Redux, do you mean they should use this inside a reducer?

Thread Thread
 
lnahrf profile image
Lev N.

Even if this could grow to a "10 out of 10" (whatever that means) complexity, you sure seem to have a very emotional reaction towards a state manager PoC that nobody uses. Have fun with that. Here is a quote from the readme:

"This project is not a replacement for other state management libraries, it's here to give a tiny, native solution for projects that wish to stay relatively small, and still enjoy state management".

Thread Thread
 
mfp22 profile image
Mike Pearson

Don't worry, people will use this. They thought Valtio was a good idea github.com/pmndrs/valtio

I'm not emotional, just direct. I have experience with dozens of state management libraries and I see what happens with each of them. People misuse Redux and it actually does turn into spaghetti code too. I'm about to write an article about that.

I just think it's a false trade-off between simplicity and scalability. I really don't like that the response to unidirectional data flow is to toss it out rather than improve upon the existing tools.

And it doesn't matter what your README says, if two things solve the same problem, even different sides of it, they're going to compete. People will use one over the other. They are substitutes. In a year I bet we see an article like "Why I chose VSSM over Redux" (or Jōtai or Zustand etc). Actually, that's kind of what this article is already.

Thread Thread
 
lnahrf profile image
Lev N. • Edited

If it doesn't matter what my readme says than it doesn't matter what I say.
Have fun with your experience with state management libraries, I will just keep doing me :)
P.S English is not my native language, not everybody is from the US.

Thread Thread
 
mfp22 profile image
Mike Pearson

I didn't notice any English mistakes.

Creating a state management library takes work and I respect that. It's a great learning exercise as well. But beyond that, you might be wasting your time, and I say that out of empathy. There are a lot of simple solutions out there already, and I would in particular recommend looking into Valtio and Jōtai. I created StateAdapt, but if bundle size matters most to you, don't use it - it's around 10kb. But if bundle size matters most to you, I'd recommend using SolidJS or Qwik, since both have built-in mechanisms somewhat similar to what you've created. I think Qwik even uses proxies too.

Thread Thread
 
dsaga profile image
Dusan Petkovic

We centrally don't need another state management library, but its good to explore different solutions and implementations, which Is what i believe this VSSM is, its perfectly fine and a great way to learn, and its not using anything other than what JS does natively.

Thread Thread
 
urielsouza29 profile image
Uriel dos Santos Souza

Image description

Thread Thread
 
mfp22 profile image
Mike Pearson

When you've never touched a complex application

Thread Thread
 
zryru profile image
Jorge Del Castillo

Sorry @mfp22 using your own phrase just being direct. You are wrong. Comparing this in terms of complexity with redux and stating that at most redux is a 5/10 in a complex application is just an incorrect fact. Redux is well known to be one of the least liked solutions due it's complexity. Even after you understand it and I personally like it and used to promote it before will always known that by many developers it is not a liked solution because of it's complexity.

Also know that you did not share your opinion alone it is clear it was an emotional response to protect redux which is completely out of the scope of the conversation in this post. I suggest next time don't overdue it and just share

Thread Thread
 
mfp22 profile image
Mike Pearson

Redux was mentioned in the 2nd paragraph. Redux has limitations. If you think Redux gets beyond 5/10, I look forward to you finding out what 6+ actually looks like, because it's only possible when event handlers have to do too much work. This is always happens when state update logic cannot be colocated with state declarations. It's the reason Flux was created. I recommend watching the original Flux + React talk a few times. Just because you haven't encountered the same problems as the Facebook team yet, doesn't mean you won't.

Thread Thread
 
mfp22 profile image
Mike Pearson

(Also I never use Redux anymore. It's just better than the knee-jerk reactions to it that never tried to understand what problems it was trying to solve.)

Thread Thread
 
lnahrf profile image
Lev N.

Mike what’s the point of arguing about such opinionated things? You’ve made your point, too bad it was not in a very nice way, but we will get over that. What is the purpose of this?

Thread Thread
 
mfp22 profile image
Mike Pearson

It must be nice not being opinionated like me. I can't help that when I see "Redux is too complicated" I get flashbacks from the battles I've fought in dozens of MVC codebases. I'm just sharing what I've learned. I would appreciate it if I were you. It's less nice to say nothing. I'm done. Good luck.

Thread Thread
 
lnahrf profile image
Lev N.

Alright mate

Collapse
 
jswhisperer profile image
Greg, The JavaScript Whisperer

does it though... Redux requires a large team to optimise a from a small scale application as it doesn't watch or manage state updates even when abstracted with higher level libraries and as your codebase grows this becomes less manageable. I find redux is a nice way to structure a react application initially but it's very unperformant and unmanageable.

Collapse
 
ivan_jrmc profile image
Ivan Jeremic

Valtio over Redux for any app size I disagree on all points from @mfp22

Collapse
 
mfp22 profile image
Mike Pearson

Give me any complex app on GitHub using Valtio and I'll make it simpler. By complex I don't mean "big" like 30 pages - I mean pages with multiple kinds of events and effects, maybe heavily asynchronous. Maybe a real-time dashboard or something. I'll diagram the data flow and show that the number of relationships and things to keep track of decreases. I'll use StateAdapt, which is more unidirectional than Redux.

Collapse
 
krymancer profile image
Junior Nascimento

Anything that uses redux is already doomed

Collapse
 
mfp22 profile image
Mike Pearson

Sure Jan

Collapse
 
the_riz profile image
Rich Winter

Something I notice is that you may be picking out only one value, but you are always returning the entire state from the getter function. I get that you're not working on it any more, but I'd look up "dependency injection" to specify the data you want in the getter function.

Collapse
 
lnahrf profile image
Lev N.

I agree, it can definitely be improved (in more than one way).
Before writing this article I went over the code for a few minutes and noticed some issues.
I don't think I will be working on it, but if you really feel like it I don't mind letting others contribute. (Or we can just leave it as it is and take mental notes, lol).

Collapse
 
steeve profile image
Steeve

I get PTSD just thinking about all the unnecessary complications - dispatchers, reducers, middleware! I just wanted to declare some variables, please make it stop.

I felt the same haha. We just want something simple, 0 deps, and performant 🤷‍♂️

Good article; keep building and creating!

Collapse
 
adaptive-shield-matrix profile image
Adaptive Shield Matrix • Edited

Jotai and Zustand - both manage to be simple, 0 deps and performant.
And they scale as good as Redux as well.

Collapse
 
steeve profile image
Steeve

Thanks for sharing!

Collapse
 
lnahrf profile image
Lev N.

Thanks for the support !

Collapse
 
pvivo profile image
Peter Vivo

qwik framework is also use Proxy behind of scene with useStore , this is one of main reason why I preferred compared react. But my daily based jobs depend on react and I think for a couple of years React stay as leading framework/library for UX.

Collapse
 
lnahrf profile image
Lev N.

Heard about qwik, I'll have to check it out!

Collapse
 
fridaycandours profile image
Friday candour

💪💪💯. State management libraries don't have to be so complicated.

For the react thing, i am one of the the software engineer behind the web development framework.
github.com/FridayCandour/cra...

Don't forget to share.

Collapse
 
slobodan4nista profile image
Slobi

I wonder why a Proxy is not built into the JS object, it is a bit limiting. There is a need, as in the Pisma project, which essentially made it but with an extra build step. Python has setattr and getattr for this purpose.

Collapse
 
lnahrf profile image
Lev N.

Yea, there is definitely a need. I would actually love to see that in the future.

Collapse
 
slobodan4nista profile image
Slobi

By the way I like your lib style, JS with d.ts 🤩 interesting and original approach, well done 👏 I like that you have subscription implemented I would put more thought into definig subscriptions, it looks a bit ambiguous.

Thread Thread
 
lnahrf profile image
Lev N.

Thanks! I honestly dislike TS quite a lot but it has it’s uses. The subscription model is definitely ambiguous, far from perfect. Honestly if I were to rewrite it today I’d probably do it differently. Either way, this lib is more of a novelty than anything at this point 🙂

Collapse
 
sindbad_x profile image
Sindbad_X

To showcase your passionate projects, you have to land on an interview first and how do you that in 2023? 😆

Nice take. Passion will push you far in programming world. Keep building things and improving your craft. The job will find you.

Collapse
 
lnahrf profile image
Lev N. • Edited

Haha yeah, you sure have to land an interview first.
I think that it is really hard for beginners and graduates, for sure. But do what you have to do, upsell yourself. Send messages to employees, to HR, don't be shy! Be professional and always interact with other people in the community.

Once you get to somebody on the phone, act like you are the most sophisticated web developer out there.

Just make sure you do not lie, and remember you do have to know enough to give off a confident vibe, but when you get the first offer it's much, much easier.

Collapse
 
dsaga profile image
Dusan Petkovic

You never know, maybe it becomes popular one day :)

Do you think it can be done by removing the additional createState function, and just initialize it with createVSSM

What do you think about me contributing just for the fun of it?

Collapse
 
lnahrf profile image
Lev N. • Edited

Feel free to, could be fun 🙂
I think it’s possible!

Collapse
 
karishmashukla profile image
Karishma Shukla

Great work 💯

Collapse
 
lnahrf profile image
Lev N.

Thank you!