[HN Gopher] Show HN: SimpleR State - simple state management for...
       ___________________________________________________________________
        
       Show HN: SimpleR State - simple state management for React
        
       Author : aenero
       Score  : 41 points
       Date   : 2021-03-20 19:34 UTC (2 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | zoontek wrote:
       | I wrote a lib with a very similar API:
       | https://github.com/zoontek/react-atomic-state
       | 
       | It rely on
       | 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.
        
       | franciscop wrote:
       | How 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/:
       | const [counter, setCounter] = useStore("counter");
        
         | runawaybottle wrote:
         | Hey, I like your version too. I'm digging these simple state
         | libraries. Really proves just how absurd Redux was when you
         | finally see the simple solution.
        
           | qudat wrote:
           | Simple state libraries are great for simple web apps, not for
           | massive, enterprise-level applications. As someone who
           | regularly investigates alternatives to redux, it still sits
           | at the top of state management.
           | 
           | These intro how-to comparisons don't do redux justice because
           | being simple to use is not the stated goal of redux. Large
           | scale, maintainable, and traceable code is the primary goal
           | of redux. When you allow anything to update your state with
           | zero form of traceability, you'll start to see the cracks in
           | these simple designs.
           | 
           | Are these new state management libraries easy to use? Sure,
           | but what happens when you have tens of thousands (even
           | hundreds of thousands) of lines of code to deal with and then
           | add major refactoring objectives in the pipeline?
           | 
           | Like others have mentioned, if you are using redux for a
           | simple to-do app, then its design principles are probably not
           | as valuable.
           | 
           | It's like thinking about time complexity for algorithms, at a
           | small enough N, even slow algorithms can compete, but as you
           | increase N, some algorithms become untenable.
        
             | runawaybottle wrote:
             | You are not the only one debugging large apps. How does the
             | wider world of programming debug stuff without actions and
             | reducers?
             | 
             | It's crazy how the Redux people either always appeal to
             | authority ('my app is bigger than yours') or can't say
             | anything more than 'I just like it'.
             | 
             | And to play the rhetorical game, what happens when you have
             | hundreds of thousands of lines of insane Redux code where
             | you have lost all sense of the state tree and need to
             | mentally cordon off one single piece of it to not go
             | insane? Kind of like how libraries like this are already
             | doing it.
             | 
             | So here is my challenge to you. Spec out an app that you
             | believe can only be solved with Redux at scale (or rather,
             | highlight the areas of the app that absolutely benefit from
             | Redux, but please provide as detailed a spec as you can if
             | you have the time, or care for that matter). I'd love to
             | hear about this incredible web app.
        
           | franciscop wrote:
           | I believe Redux is good when you have 3+ people working on
           | the same project front-end, and absolutely necessary when you
           | have 10+. This makes it work great with the Facebook, Airbnb,
           | etc. of the world.
           | 
           | Which is totally fine, but not your everyday problem for the
           | rest of us! I'm very happy to see all of these versions pop
           | up as well.
        
             | runawaybottle wrote:
             | What makes that objectively true? I'm looking at these
             | APIs, and at least two of these solutions are plain better
             | design.
             | 
             | What about this would get worse with more engineers or
             | higher caliber engineers that Redux clearly avoids?
        
               | franciscop wrote:
               | It formalizes how data is created, accessed and modified.
               | Instead of multiple places trying to modify some specific
               | data ad-hoc and with possible collisions/changes, now you
               | have a mores strict way of dealing with data.
               | 
               | Basically the Flux architecture. See from 10:20:
               | 
               | https://www.youtube.com/watch?v=nYkdrAPrdcw
        
               | aenero wrote:
               | I see what you're saying here, and actually agree at some
               | level.
               | 
               | But there is always an alternative, IMHO. If the project
               | has a good code structure and follow equally good coding
               | standards and review process, using simple un-
               | opinionated/flexible libraries would not be a liability
               | with "scale" (in terms of team/project size).
               | 
               | And there's one advantage of simpler approaches for
               | growing teams: faster/easier onboarding. Let's face it,
               | even good React/Redux developers can understand simpler
               | code faster.
               | 
               | Just an alternative thought. But I completely get your
               | point.
        
               | runawaybottle wrote:
               | Ok, so what are the actions/reducers nonsense about?
               | 
               | I'm just not seeing the argument here, and I've been on
               | multiple redux applications on teams of various sizes. We
               | always seem to create layers of indirection to do the
               | simplest possible state update.
               | 
               | We adopted Dan Abramov's mental model, and my god, it was
               | a labyrinth.
        
               | acemarke wrote:
               | You might want to read my "Tao of Redux" posts and Dan's
               | "You Might Not Need Redux" post, which explain why Redux
               | was designed the way it is:
               | 
               | - https://blog.isquaredsoftware.com/2017/05/idiomatic-
               | redux-ta...
               | 
               | - https://blog.isquaredsoftware.com/2017/05/idiomatic-
               | redux-ta...
               | 
               | - https://medium.com/@dan_abramov/you-might-not-need-
               | redux-be4...
               | 
               | Ultimately, it's about putting a deliberate separation
               | between "what happened" in the UI and "how the state is
               | updated", writing as much of your state update logic as
               | pure functions, and being able to use that indirection to
               | enable tracing state updates over time via the DevTools.
               | 
               | Also note that our official Redux Toolkit package is now
               | the standard recommended way to write Redux logic, and it
               | simplifies most of the Redux code you'll write:
               | 
               | https://redux.js.org/tutorials/fundamentals/part-8-modern
               | -re...
        
         | aenero wrote:
         | Following 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.
        
       | brainless wrote:
       | If 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
        
       | The_rationalist wrote:
       | If 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 (though I find Mobx to be
       | perfect)
        
         | aenero wrote:
         | For 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 wrote:
           | Out 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
        
             | aenero wrote:
             | Actually 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.
        
         | rtcoms wrote:
         | I'm yet to decide between Rematch and easy-peasy
         | 
         | https://easy-peasy.now.sh/
        
         | acemarke wrote:
         | Have you looked at our official Redux Toolkit package?
         | 
         | https://redux.js.org/tutorials/fundamentals/part-8-modern-re...
         | 
         | https://redux-toolkit.js.org
        
       | snissn wrote:
       | hi 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 wrote:
         | Hi. 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
         | 
         | 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.
        
       | zeroonetwothree wrote:
       | I 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/
        
       | dkarras wrote:
       | So 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 wrote:
         | The optimizations on preventing unnecessary re-renders are
         | well-documented here:
         | 
         | https://simpler-state.js.org/recipe-transforms.html
         | 
         | Thanks for your reply.
        
         | benjaminclauss wrote:
         | I used to see a lot of online sentiment that Vue would "take
         | over" where React is used now. Is this still the case?
        
       | sdfhbdf wrote:
       | Congrats on launching :) How does it compare to React Context
       | that is built-in?
        
         | aenero wrote:
         | With 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 wrote:
           | > 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 wrote:
             | Maybe "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 wrote:
               | Not 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 wrote:
               | Yup 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.
        
           | sdfhbdf wrote:
           | Thanks for the answer.
           | 
           | > multiple times faster than when using Context
           | 
           | Oh cool! Do you have some benchmark results for that? Would
           | be awesome to post them in the README if you can.
           | 
           | > simpler because you don't have to use Providers at all
           | 
           | I think the Provider pattern is part of the functional
           | programming pattern with React, so while I do agree it might
           | be harder to get used to but it underlines the no side-
           | effects affecting the state of a given React components and
           | its children.
           | 
           | At scale proper action, reducer pattern is helpful to manage
           | a complicated state tree to still make it functional, easily
           | testable and giving the same end result as a function of
           | state.
        
       | jhunter1016 wrote:
       | While 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 wrote:
         | > 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.
        
       | aenero wrote:
       | 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.
       | 
       | I wrote this library with the hope that this might be it. Any
       | ideas/suggestions how to further simplify it would be super!
        
         | [deleted]
        
         | christophilus wrote:
         | Looks kind of similar to something Mithril does (or used to
         | do). Ergonomically, I prefer `counter(0)` to `counter.set(0)`.
        
         | brainless wrote:
         | I 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 wrote:
           | You'd be happy to know those are supported and documented at
           | 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-orchestrators.html
        
         | xixixao wrote:
         | It'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 wrote:
           | Hi. 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.
        
       | revskill wrote:
       | What'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]
        
       | rajangdavis wrote:
       | This 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 wrote:
         | Depending 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 wrote:
           | I 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 wrote:
             | It 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.
        
       ___________________________________________________________________
       (page generated 2021-03-22 23:03 UTC)