DEV Community

Arnel Enero
Arnel Enero

Posted on • Edited on

Can React state management get any simpler than this?

I'm one that loves simplicity in things. So despite the plethora of state management libraries for React, I have always wondered what the absolute "simplest" approach would be.

After some time on the drawing board, I think I've come up with just that. And today I'm happy to share with you SimpleR State. (yes, with capital "R", for React πŸ˜‚)

Imagine being able to implement shared state in just 2 easy steps!

Step 1: Create an entity (shared state) and actions (updater functions)

// counter.js

import { entity } from 'simpler-state'

export const counter = entity(0)

export const reset = () => {
  counter.set(0)
}

export const increment = by => {
  counter.set(value => value + by)  
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Use the entity in your components with hooks

import { counter, increment, reset } from 'counter'

const CounterView = () => {
  const count = counter.use()

  return (
    <>
      <div>{count}</div>

      <button onClick={() => increment(1)}> + </button> 
      <button onClick={reset}> Reset </button>
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

(Other components can use the shared counter the same way.)

It's that simple! But that's just a teaser, it can actually do a whole lot more!

Here are some of the design goals for this library:

  • Minimalist API; no complicated concepts or boilerplate
  • Use plain functions to implement state changes (including async)
  • Largely unopinionated with flexible syntax
  • Extremely simple to unit test state changes
  • Highly extensible with plug-ins (e.g. persistence, logging, dev tools)
  • Full TypeScript support with uncomplicated types
  • Made specifically for React, and built on React Hooks
  • Multiple times faster than context/reducer solution
  • Tiny, just around 1 KB (minified + gzipped)

If these benefits interest you, give SimpleR State a try. You can learn more about other things you can do with it at simpler-state.js.org. Yes, I wrote full documentation! πŸ€“

And if you like this library, and/or the simplicity/concept behind it please give it a star on the GitHub repo to let me know. πŸ˜€πŸ‘Œ

So tell me, can the library get any simpler than this? I'd love to hear your suggestions. Goal is to get it closer to its bold claim of "simplest", not to compete with other libraries as the "best".

I opened a Request For Comments (here) on GitHub. Your comments and suggestions would be greatly appreciated. Feel free to drop me a comment here πŸ‘‡ too.

Another P.S. -- I have prior art called react-entities which has already been out for quite some time, and used by our company in production. SimpleR State is an evolution, based on the same stable core, but with completely different (much simpler) API.

Latest comments (76)

Collapse
 
avkonst profile image
Andrey • Edited

Yes, it can get simpler, and it also needs to be more scalable and more powerful. Have a look at the Hookstate. It is as simple as React.useState API. It is hard to get any simpler than this, but at the same time Hookstate supports most (if not all) of state management needs, has got very impressive performance (Recoil, try to beat this: hookstate.js.org/docs/performance-...) and can be extended with custom plugins when needed. (Disclaimer, I am an author of the project)

Collapse
 
robvirtuoso profile image
robvirtuoso • Edited

So I see this kind of post again from the proud author of HookState, making comparisons as if it is a competition of who makes the best library.

Have you even tried these libraries being discussed in posts that you are hijacking? In this particular case you just enumerated what the library already does, as if they are missing in the library... so I guess you didn't bother to look.

I did stumble upon HookState earlier this year, and found that it overrides useState (by using the same name), and then changes its construct altogether, uses inconsistent parameter semantics for global vs. local usage, and on top of that, introduces a different output type for async state while using the same useState construct (talk about unpredictability!). Why would you do that??? After that, I looked elsewhere sorry.

(See, even if I am personally biased towards a different library, I didn't even feel the need to compare. I just objectively say why I didn't pick up HookState.)

Dude, one piece of unsolicited advice, stop promoting your own library in discussions that talk about another library. It is quite distasteful, and just brings a bad impression on your library to be honest.

Collapse
 
avkonst profile image
Andrey • Edited

"hijacking?"
No, I expressed my opinion on the asked question if it can be any simpler.

"so I guess you didn't bother to look."
I looked at this.

"Why would you do that (use the same function name)???"
Because whatever the argument is, it gives you back the State object, which has got the same functionality regardless if a state variable comes from local variable, global variable, if it is a Promise or not.

" it overrides useState"
It does not override it. It just have got the same name because it does the same (for the case of the local state). If it is no-no, there is an alternative name 'useHookstate' or you can name alias on import or you can use module prefixes.

"different output type for async state"
No, you are not right with this statement. It is still an object of the same type with the same API and functionality.

"After that, I looked elsewhere sorry."
Good on you. I am quite glad you moved.

"I just objectively say why I didn't pick up HookState."
I got you objection comments on board. Thanks
Here is another view on Hookstate by someone else, who actually see it valuable: areknawo.com/top-5-react-state-man...

"stop promoting your own library in discussions that talk about another library"
Thanks for the advise. I hope you will take the effort to put down similar promotions everywhere around the internet? or maybe start with this article...
People pointing out to so many other alternatives all over the place. Many people said me "Thank you for the awesome library" after going to it from a "promotion" comment like this. So, I guess if there were no "promotional" comments people would not discover it and some of them would not get the tool which solves a real problem for them and makes them happy. I guess if I had a twitter account with millions of subscribers like some other "more well known" libraries use, I would not need to comment anywhere or even pay attention to comments like yours. At the same time I am a developer and prefer to write code, instead of developing marketing presence and twitter accounts. The tool I published solved a problem for me (no other state management library, I am aware of, solves the problem of performance of frequent deeply nested large state updates). I published it with the hope it makes life easier for somebody else too. And it did. I appreciate many will not bother even to look at it, because it does not come from Facebook or alike. But a few will and do use it, and it is enough.

Thread Thread
 
robvirtuoso profile image
robvirtuoso • Edited

I thought it prudent to repost here what I wrote in response to another conversation with you elsewhere... so that I may be completely fair to you. I do appreciate the effort you put into your library and for maintaining a good demeanor despite criticism.

---- Repost starting from here ---

I'm not trying to antagonize you. I just hate the idea that independent open source contributors like you will get a bad reputation due to their posts like this. I find publishing open source libs a noble thing to do, especially for people who don't earn a dime from it. You seem like you belong to this category, so I appreciate your efforts. I actually help promote work of libs that I personally use, as a way of giving back to the author/maintainer. If your posts triggered a bad reaction from me, it may happen with others too. So again I wouldn't wish you that misfortune.

You may not be asking for advice from me, but if it was me I would not want people thinking that I'm doing this to compete with the big guys (Redux, Recoil, etc.) which are backed by a big corporation and fanboys... And nor would I ever say that my lib is superior to another , popular or new one.... open source is not a popularity contest after all. As long as a number of people actually use your library, i.e. it is helping some folks out there, it means you already are doing a good job.

Collapse
 
bcncodeschool profile image
George K.

Hi Arnel,
I was wondering if you would be interested in joining an online meetup to introduce SimpleR State (which I personally find awesomely simple :) ) to the audience of JS community of Barcelona.
Thanks!

Collapse
 
appurist profile image
Paul / Appurist

As a fun project I tried to make the simplest reactive state, came up with this:
codepen.io/appurist/pen/QWdWzag?ed...

It too might be useful for others trying to avoid more complex framework state management.

I think it's quite a bit simpler, supports any types including subfields deeply nested within objects.

There's a more advanced example here:
github.com/appurist/reactivator/wi...
but if you look at the output, you'll see how capable it is (yet so simple to use).

Collapse
 
appurist profile image
Paul / Appurist

Simpler example with a reactive state object here:
github.com/appurist/reactivator/wi...

Collapse
 
arcticspacefox profile image
ArcticSpaceFox

This feels more then useState, doesnt it?

Collapse
 
thomasburleson profile image
Thomas Burleson

The Zustand API [from the React Spring guys] is amazing and clean:

1) Use create(<callback to build>) to build a store, initialize state, and get a hook associated with that store
2) Use the hook (eg useStore(<query selector>)) to query/select data from the store.

Whenever that data slice changes, the hook re-emits and the component can re-render with up-to-date state.

@see github.com/pmndrs/zustand

Collapse
 
skyjur profile image
Ski • Edited

What happens if you need multiple instances of entity?

Collapse
 
arnelenero profile image
Arnel Enero • Edited

You can treat an entity just like a variable. Just declare as many entities as you want. Don't think of an entity as a class that you need to "instantiate".

For example:

export const counterA = entity(0)
export const counterB = entity(0)
export const counterC = entity(0)
// and so on...
Enter fullscreen mode Exit fullscreen mode

And if you want to avoid declaring many actions that all look the same, you can do something like this:

const newCounter = () => {
  const counter = entity(0)
  const increment = by => { counter.set(value => value + by) }
  const reset = () => counter.set(0)

  return { counter, increment, reset }
}

const counterA = newCounter()
const counterB = newCounter()
const counterC = newCounter()
Enter fullscreen mode Exit fullscreen mode

This library is flexible. You can do it however you prefer.

Collapse
 
skyjur profile image
Ski • Edited

Don't think of an entity as a class that you need to "instantiate".

It's a very useful thought though - as every variable needs to instantiated with initial state. If it's class or not doesn't matter at all.

What I see here in your examples is completely no different of just using useState(). Thus I completely miss the point that you're trying to achieve.

const useCounterStore = () => {
  const [counter, setCounter]= useState()
  return { 
      counter,
      increment(by) {
         setCounter(counter+by)
      },
      reset() {
         setCounter(0)
      }
  }
}

function SomeComponent() {
   const counterA = useCounterStore()
   const counterB = useCounterStore()
   const counterC = useCounterStore()
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
arnelenero profile image
Arnel Enero

Your example would not be "shared state", is it?

Collapse
 
muhammadawaisshaikh profile image
Muhammad Awais

React Hook for Context is great as well. It’s simple and supper fast πŸ™Œ by the way amazing work you did also

Collapse
 
lexiebkm profile image
Alexander B.K.

In my last project, for local state, I simply used React traditional way, But for global state, due to time constraint (Mastering Redux would take longer time) I used reactn : github.com/CharlesStover/reactn
It was easy to use and worked well.
However, now I am going back to consider Redux again, because, in addition to the things mentioned in the documentation, for motivation to use it, I think I like the idea of storing states centrally (via store). Other reason for using Redux is because it is likely I will be working in a team that uses Redux. In my last project, I worked as a lone full-stack developer, so I could pick anything suitable.
Still, it will take time for me to learn and really use it in a real project. So, I also consider using Context and other built-in React API (useReducer) for achieving the same purpose, i.e dealing with global state.

Collapse
 
krimotemam profile image
Krimo

Cool project man keep up the good work

Some comments may only be visible to logged-in visitors. Sign in to view all comments.