8 ms·
Show HN: SimpleR State – simple state management for React
- aenero 6y agoI'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. I wrote this library with the hope that this might be it. Any ideas/suggestions how to further simplify it would be super!
- brainless 6y agoI really like what you have done here. I have two questions: 1. Do you mind sharing examples with async calls? This is very common and I really look for this example as quick as possible 2. How you do connect two stores? Say one triggers and update in the other... Thanks a lot :)
- aenero 6y agoYou'd be happy to know those are supported and documented at https://simpler-state.js.org https://simpler-state.js.org Specifically, look at these "Recipes" pages: https://simpler-state.js.org/recipe-async.html https://simpler-state.js.org/recipe-async.html https://simpler-state.js.org/recipe-orchestrators.html https://simpler-state.js.org/recipe-orchestrators.html
- christophilus 6y agoLooks kind of similar to something Mithril does (or used to do). Ergonomically, I prefer `counter(0)` to `counter.set(0)`.
- deleted 6y ago[deleted]
- xixixao 6y agoIt’s not clear how to define a new entity out of another one using a selector. So perhaps instead of/in addition to `x.use(foo)` you might want `x.select(foo).use()`. Not sure if simpler but something I’d be missing/would feel inconsistent.
- aenero 6y agoHi. SimpleR State makes use of selectors without creating a new entity (unlike atoms in Recoil, for example). It uses the more classic paradigm used by popular libs like React Redux where you just use selectors to filter/transform the "received" state to the format required by the component, and not to "create" a derived state per se. I hope it makes sense.
- zoontek 6y agoI wrote a lib with a very similar API: https://github.com/zoontek/react-atomic-state https://github.com/zoontek/react-atomic-state It rely on https://github.com/facebook/react/tree/master/packages/use-subscription https://github.com/facebook/react/tree/master/packages/use-s..., which make it safe to use in concurrent mode and the implementation a lot simpler.
- brainless 6y agoIf you want a simple and elegant state management module then check out Zustand. I have been using this for a year or a bit more and am absolutely happy with it. https://github.com/pmndrs/zustand https://github.com/pmndrs/zustand
- sdfhbdf 6y agoCongrats on launching :) How does it compare to React Context that is built-in?
- aenero 6y agoWith this one, you can write granular shared states (multiple "entities") without creating layers and layers of Context Providers in your component tree. Since data is not encapsulated inside React component tree, I found it to be multiple times faster than when using Context. And one thing that's perhaps the most obvious... it's simpler because you don't have to use Providers at all.
- jeswin 6y ago> Since data is not encapsulated inside React component tree, I found it to be multiple times faster than when using Context. What do you mean by data being encapsulated in the tree? How does that make it slower?
- aenero 6y agoMaybe "encapsulated" is not the right term when I simply meant "scoped". I tried scoping the entities using Context in some prior art which we use in production. Some colleagues kindly gave me some benchmark results and the version without Context (external/module-scope) was faster. I'm not trying to debate against Context here. In fact, there's nothing that would stop anyone from using SimpleR State's entities with Context API.
- jeswin 6y agoNot that I'm a fan of Context (or even React); but without publishing the benchmark code or specific technical arguments, it's hard to support a claim about slowness or of speed.
- aenero 6y agoYup agreed. That's why I stated it as "I found it to be...", coz I'm not trying to convince everyone else LOL. It's never my intention for this library to try and be the "best" out there. I simply want to create what I sought for, which is the closest to the simplest approach I can think of. And to share it to the public, in case someone out there is looking for the same thing I am, and maybe it could help that someone. That's what open source is for, after all.
- dkarras 6y agoSo this makes things very similar to how Vue does things. Vue 3 with its encapsulated reactive library also works this way. But immediately I wonder how it works with React innards, do I have to optimize rendering? Does it do wasteful re-renders? How does it affect diffing?
- aenero 6y agoThe optimizations on preventing unnecessary re-renders are well-documented here: https://simpler-state.js.org/recipe-transforms.html https://simpler-state.js.org/recipe-transforms.html Thanks for your reply.
- benjaminclauss 6y agoI used to see a lot of online sentiment that Vue would "take over" where React is used now. Is this still the case?
- jhunter1016 6y agoWhile I finally bit the bullet and learned redux a couple years ago, I tried for a long time to avoid it. It’s overly complex for the tasks it is often trying to solve. I like this solution because it’s simple, testable, and global.
- capableweb 6y ago> It’s overly complex for the tasks it is often trying to solve. That's a bit like saying a excavator is a bit too complex to hammer nails. Yes, that's true, but that was not why we created the excavator in the first place. Same with Redux. Initially created to get rid of big, hairy and complex balls of state. If you use it in your basic CRUD, you're probably using the wrong tool rather than the tool is wrong itself. Each tool has it's place in our toolboxes. It's our job to decide when to use what tool.
- franciscop 6y agoHow do you define "simple"? Simple is a very complex topic :) For example, in React the common way of using hooks is `useMyhook()` where "Myhook" is whatever you name it, like "useState", "useEffect", etc. So I'd argue that an API that follows the conventions in a platform is simpler than one that rewrites them. In this specific situation in the first demo, I would expect to have a hook called `useCounter()` instead of `counter.use()`. Furthermore, since we are manipulating state again the convention in React for state manipulation is to return the value and then the setter, like: const [counter, setCounter] = useCounter(); Now I understand since it's a global state we cannot give it a local initial value to avoid race conditions, so that's IMHO about as simple as you can get. I didn't do that, but I believe I got pretty close with my own React state management library https://statux.dev/ https://statux.dev/: const [counter, setCounter] = useStore("counter");
- aenero 6y agoFollowing React conventions is certainly an option and is supported by SimpleR State's unopinionated and flexible syntax. 1. It was inadvertently removed from the documentation, but these are equivalent: const count = counter.use() const count = useEntity(counter) but the `counter.use()` was chosen in the documentation due to more feedback that requested this "simpler" format (i.e. no need to import `useEntity()`. But again, to your point I will restore the mention of `useEntity` in the documentation. 2. As for the [state, setState] convention, think of useEntity more like useContext than useState. Then it gets simpler. 3. I would also argue that since this is "shared" state, the developer might (again, the library is not opinionated on this) choose to separate the logic of updating shared state. For this reason, I didn't see any reason to provide a setter through the hook, when you can access the setter from anywhere via something like counter.set(). Conforming to useState convention was not justified in this case, especially since useContext convention equally makes sense for shared state. 4. To suit whatever convention, you can always do something like this alongside the definition of the entity: export const useCounter = counter.use I want to point out that SimpleR State provides the flexible constructs to allow the developer to tailor it to their preferred convention. Thanks for your feedback.
- runawaybottle 6y ago
- The_rationalist 6y agoIf you missed it rematch is very promising: It has the feature completeness and interop of redux while being much simpler https://github.com/rematch/rematch https://github.com/rematch/rematch (though I find Mobx to be perfect)
- rtcoms 6y agoI'm yet to decide between Rematch and easy-peasy https://easy-peasy.now.sh/ https://easy-peasy.now.sh/
- acemarke 6y agoHave you looked at our official Redux Toolkit package? https://redux.js.org/tutorials/fundamentals/part-8-modern-redux https://redux.js.org/tutorials/fundamentals/part-8-modern-re... https://redux-toolkit.js.org https://redux-toolkit.js.org
- aenero 6y agoFor folks who use Redux, the React Redux library has gotten much much more developer-friendly than it originally was. The other libraries like Easy Peasy and Rematch serve a nice syntactic sugar, though.
- acemarke 6y agoOut of curiosity, any specific features of Rematch and Easy-Peasy that you specifically like that aren't covered in Redux Toolkit? I've actually got an RTK issue open asking for ideas and concepts that we can learn from them: https://github.com/reduxjs/redux-toolkit/issues/527 https://github.com/reduxjs/redux-toolkit/issues/527
- aenero 6y agoActually I was favoring the official React Redux stuff in my comment. Just trying to balance it out by mentioning that Rematch, Easy-Peasy and other libraries in the ecosystem all have their own place in the open source world, even if they can be considered different flavor icings on top of the same cake.
- revskill 6y agoWhat's wrong with @redux/toolkit ? Just incrementally add reducer and you're good to go. With redux-thunk, devtools built-in, i don't need much more. Better state management to replace redux to me requires another approach (maybe atom like ?) I use Redux not (just) because its ecosystem and tooling. It's simply just because i found its API simple to use and scale.
- deleted 6y ago[deleted]
- zeroonetwothree 6y agoI have liked Recoil, it works really well for things like async loading. For more basic stuff I just use the useState hook directly. https://recoiljs.org/ https://recoiljs.org/
- rajangdavis 6y agoThis is a general question, but how do you structure state with hooks if your React app is mostly composed of hierarchical, dynamic components? For example, let's say the initial UI lets you create one or more of Component A (only one type of component); Component A can create one or more Component B (which can be many types of components); and Component B can create one or more of Component C (which can be many types of components). The app is to model some configuration for some physical devices that are interconnected. I have something working today using the "useImmerReducer" package and updating parent components whenever children components change, but was curious if there is a more established pattern?
- aenero 6y agoDepending on which principles/patterns you are applying, you can go as elaborate as using something like Recoil for that (I think this might be a great application of Recoil as it deals with atomic data), or you can choose to go simple with a tree-type data structure that parallels your component tree. But first thing you should identify, IMHO, is which of those states are _really_ "shared" states. Coz some of those state values are probably better kept local.
- rajangdavis 6y agoI was looking at Recoil this weekend and it does seem like a good use case, I just wasn't sure how it would simplify what I was doing. I think I may have applied a bad design as I converted all of my React Components to React functions. Is it possible to instantiate Recoil atoms inside of for loops? Basically, I would like to be able to scope state locally to React functions, but hooks don't let you do that, they have to be completely abstracted.
- aenero 6y agoIt would be counter-intuitive if I endorse a Recoil-based solution on this thread that talks about a different library, LOL. But since I want to help as much as I can, my advice is, regardless of which library you choose, or which approach (atomic vs. monolithic/structured)... start with analyzing which parts of the state in your app really are supposed to be "shared" state. I have a feeling you may be trying to use "shared" state libraries to manage state that only the individual components would actually need. Do those dynamic components actually need to share data? The answer to that is the first important consideration, IMHO, before you can go forward. Good luck.
- snissn 6y agohi thanks for building this - i'm struggling with finding a good state management react workflow too. could you speak a bit about the other alternatives that are around and when Simpler is better, and when it isn't? Would help me have more confidence to pick this up.. thanks!
- aenero 6y agoHi. There are LOTS of much more popular libs you can choose from. My library does not intend to compete as the "best" library, but it has a very specific set of goals, the topmost of which is simplicity through a minimalist API. Don't get me wrong. SimpleR State is a "complete" library despite the simple API. It supports things like selectors, async actions, and plug-ins. And soon, it will come with built-in plug-ins like persistence, Dev Tools, validation, etc. Everyone has different priorities when choosing a library, so I suggest going through the design goals that I highlighted in the README file, or complete documentation here: https://simpler-state.js.org https://simpler-state.js.org and see if it fits what you're specifically looking for in a library. At the end of the day, all these libraries are just React code. In that sense they differ in terms of patterns/principles behind their implementation, but maybe more importantly, in the API/syntax (which is what immediately matters to the developer using it). This is what I can confidently say that SimpleR State delivers... one of the simplest APIs you can find.