DEV Community

Cover image for Introducing Object Hooks: Mutable State for React 🤯
Ryan Kahn (he/him)
Ryan Kahn (he/him)

Posted on

7 1

Introducing Object Hooks: Mutable State for React 🤯

The idea I started with is: What if we could write state changes in react as mutations on a persistent reference? 🤔 So I wrote the code to make it work! The basic concept is summed up in the code from the banner image:

import React from 'react';

import { useObject } from '../hooks/useObject';

export const Counter: React.FC = () => {
  const [state] = useObject({
    count: 1,
  });

  return (
    <button
      onClick={() => {
        state.count++;
      }}
    >
      {state.count}
    </button>
  );
};
Enter fullscreen mode Exit fullscreen mode

In this case, state is a persistent reference that you can mutate (state.count++). The consequences of this change are fairly interesting. For one, you can create these objects with a class! So the above example could be rewritten as:

import React from 'react';

import { useInstance } from '../hooks/useInstance';

class Counter {
  count = 1;

  increment() {
    this.count++;
  }
}

export const Counter: React.FC = () => {
  const [counter] = useInstance(Counter);

  return (
    <button
      onClick={() => {
        counter.increment();
      }}
    >
      {counter.count}
    </button>
  );
};
Enter fullscreen mode Exit fullscreen mode

Also, if you need to subscribe to to changes in the objects outside of a component function, they implement the AsyncIterable interface, so you can await their next state, or for await future states in an async function. Here's a logger class that subscribes to a counter!

class CounterLogger {
  constructor(
    private counter: Counter & AsyncIterable<Counter>
  ) {}

  log(count: number) {
    console.log(`Count is: ${count}`);
  }

  async watch() {
    this.log(this.counter.count);

    for await (const { count } of this.counter) {
      this.log(count);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

There's more to it, and there will be more as the project progresses. I wanted to share what I have in its current "state" 😉 to give everyone a chance to contribute their thoughts and ideas! If you're interested, clone the repo and try it for yourself! Or leave a comment or question on this post! All are contributions, all are welcome. 🔰

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (7)

Collapse
 
yannickfricke profile image
Yannick Fricke •

Hey Ryan!

Someone else posted a link to the GitHub repository yesterday and I quickly took a look on it! Seems very interesting! I also had some thoughts about a resettable state and published my code :D

github.com/YannickFricke/react-res...

Feel free to leave any comments! :)

Collapse
 
shiftyp profile image
Ryan Kahn (he/him) •

I like it! I use a similar pattern in object hooks!

Collapse
 
yannickfricke profile image
Yannick Fricke •

To be honest, I was inspired by your library! :)

Thread Thread
 
shiftyp profile image
Ryan Kahn (he/him) •

A great library would be so inspiring and accessible that you could and would want to adapt parts of it or ideas from it for your own use. I'm happy it resonated with you, and you were able to pick up on the pattern and adapt it!

Thread Thread
 
yannickfricke profile image
Yannick Fricke •

I just wanted this single part only without all the other stuff you have in your code.

KISS - Keep It Stupid Simple

Someone could argue that relying on to much dependencies makes the technical debt bigger and bigger. But this is so simple, you could even write it yourself :D

Thanks again for the idea! :)

Thread Thread
 
shiftyp profile image
Ryan Kahn (he/him) •

The extra bit that bridges the diff between resettable state, and mutable state: is taking the setState function and calling it whenever properties on the object change. If that's not a feature you want though, then resettable state is a good solution!

Collapse
 
tylerlwsmith profile image
Tyler Smith •

Yo Ryan this is awesome!

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay