Poll: State management: Redux, MobX, ReasonML


#1

Based on your knowledge in ReasonML, and the current state of React and Reason (pun intended), if you had to recommend a state management solution for medium-complexity webapp (using Apollo GraphQL too), which solution would you recommend to a JS development team:

  • Redux (possibly with Kea)
  • MobX (possibly with mobx-state-tree)
  • ReasonML (possibly with addition of Redux, Mobx, or just React Context)
  • Something else

While people here might be tempted to recommend ReasonML, I need to consider Ease of use + Learning curve in addition to the Maintainability of code. Also, I need to consider that the state needs to be accessed from outside of ReasonML (i.e. perhaps via React Context, or otherwise also need Redux or Mobx).

One of the reasons I’m curious about this is because I really like the reactive approach of MobX (seems to simplify the design and boilerplate, to me), but I realize that it’s not the “correct”/functional way to manage state.

Thanks for your input, I appreciate any insights I can glean from your experience, etc.


#2

I wouldn’t recommend ReasonML as an immediate escape from ES6 and the React+Redux+npm ecosystem. It is to me a superior way of building user interfaces, but it is also a programming language and a different, better way of designing programs, requiring a sizable learning effort. This is different in magnitude from learning the MobX API over Redux for example, or even the shift from direct DOM manipulation to something like React.

To try to answer some of your questions - Redux is baked into the ReasonReact component model and thanks to static typing, it is robust, succinct, and the API much more ergonomic - self.send(StartDownload) is better in many levels than dispatch(function() {return {type: START_DOWNLOAD}}()). I also find that complex state trees and passing props down deep hierarchies isn’t as much of an issue thanks to static typing, compared to plain ES6.

I would however recommend studying static typing, functional programming, Reason/OCaml the language, and its flavor of modules and functors before committing it to a a commercially critical project. You might also want to consider Elm, which carries the many benefits of ReasonML, is thoroughly beginner-friendly, has a distinctive aesthetic and considers different trade-offs than Reason. Both these languages fall into the statically-typed functional programming paradigm so the mental models are very similar.


#3

Thanks @jasim, I can see what you’re saying.

Re: Elm, I don’t want a beginner friendly language, I want an industrial strength language. However, having said that I’m curious about TEA for Reason, since it seems Reason is lacking a lot of good examples, patterns, and architecture.

I also still wonder about “transparent” reactive programming like mobX. Is it inherently bad? I can understand that on a large scale it could create a mess, but on a small scale it seems succinct and good.


#4

Depends on the capability of your team, your timelines, the requirements of the business, etc. Does your team know any of the state management software out there already, and at what level? Do you practice pretty strong TDD principles? Are they familiar with functional programming paradigms?

Do you have senior devs with sufficient mentoring capability such that they can help less experienced developers work with reason? If you do, then it might be a reasonable choice. You could implement it just for state management, but leave the rest of the application to straight JS. Without that kind of ability though, I would caution you against throwing them in to the wolves. I’ve been working with reason for a little under three months, and it hasn’t always been a great experience. I’m becoming more comfortable with it as I gain fluency, but not everyone has a couple of months to burn.

Redux has a lot of support, articles, examples, alternative implementations, and is relatively easy to grasp. It’s probably the best choice for getting things done. Without good testing and reviewing, you might end up with a bunch of non-obvious errors that you weren’t expecting though. Reason/static typing won’t save you from all of them, but it will give you that safety. It will also give you that kind of frustration.

Oh, and reason isn’t super great with floats. If you’re futzing around with numbers here, there, and everywhere, maybe not fab. Up to you?


#5

I totally agree and looking so forward whats coming for ReasonML and the front-end community.

So if somebody would asking me right now for a real customer project,

i would recommend you a very conservative approach with ReactJs and MobX (which is a great and powerful state management system with little boilerplate like you already mentioned @vonwao ) or Redux (which brings a bit more boilerplate and more code to the table but feels more predictable and maintainable imho).

You simply have tons of examples, best practices and already production proofed libraries and components which helps you developing fast and reliable front-end applications in ReactJs.

Nor or less, if you have the chance and the budget to be a bit more on the edge, go for ReasonML.
I have the feeling in two years, nobody will ask this question anymore :joy:


#6

id love to see reason-apollo + graphql_ppx work with apollo-link-state



#7

I’ve found that once I started using Apollo to handle remote data, a med size app (~100k loc) I really only needed to use two things for state:

global state
I used to use redux for global app state but React’s new context API is a perfect fit for state that’s used all over the app like modals, user/login info, alerts, etc… Reason now has a library to emulate the React 16 context API and it works pretty well for me in my simple-form library.

If the app has a use case where certain “chunks” of the app have their own shared state that needs to be retained after the component is torn down/rebuilt, i’ll use a key for foo_state where that can live (this is assuming it’s too verbose to pass down local state, as that’s preferred).

local state
Most of my local state can either be consumed normally or passed down into the children {parentState, setParentState}. Apollo is typically used a lot here too in a container component (to make it easy to test). I’ve found Reason React’s reducer to be so nice.

@vonwao what have you found since usage of Reason since April (start of thread)? I’m starting a greenfield app next month and i’m also hoping to use it at work on a customer support pages (easy win) so i’ll find out more soon.


#8

Thanks, this is helpful. To be honest, I have not yet built anything major in Reason React. I will take a look at simple-form to see how context works.

don’t qutie get that, you use a key where?

I’m also not familiar with this.

Reason-react looks very good, the reducer component seems simpler than React.JS + Redux. I think reading more examples would be helpful for me and others too, I still don’t feel very comfortable with it, I’m used to the React-JS API (React classes and stateless functional components). Reason is still pretty foreign to me, but I’ll learn it soon, at my pace!


#9

Ah sorry for the terse explanation before.

For the global state when I said foo_state I just meant I can setup a global state with a shape that resembles something like this:

let make = (_children) => {
  getInitialState: () => {
    sidebar_state: {step: 1, currentStepName: "Shipping"},
    modal_state: {modalText: ""},
    current_theme: {type: "dark"},
  },
}
...

And then you could pass this state and a setter function down via context. The setter function would ideally only update one piece of the state. The sidebar/modal/etc… isn’t a great example but in theory if you had some state that had to be global this could be something to use. I really try not to use context though unless it’s a maintenance win (like having 100+ form inputs).

For the second part, the local state, a parent component… lets say a “PostsPage” component could contain local state with the the state needed for posts and comments, and it passes it down (prop drilling) to all the children that need it. I did put setParentState out of habit with React JS, but in Reason it would be more like dispatchParentAction and the child would use it to dispatch an action that would trigger the parents reducer to update it’s state… maybe something like this (just pseudo code, not sure if it compiles)

let component = ReasonReact.reducerComponent("PostsPage");

let make = (_children) => {
  {
    ...component,
    initialState: () => {/*...*/},
    reducer: (action, state) =>
      switch (action) {
      | EditPost(newText) => handleEditPost(newText)
      },
    render: self => {
      <div>
        <Posts postsState=self.state  postsDispatch=self.send />
      </div>
    },
  };
};

This has gotten the job done for me but i’m still learning as well. @jasim had a better example of this, only they used a data structure outside of the React tree all together to separate business rules from the interface and passed it in and used that as the state (eg the data doesn’t actually have to be in the same file… which is great).

I would definitely checkout this whole thread but here’s the full context and an example of the methodology:

I’m going to try and refactor a side project (realtime crypto dashboard) to use this as I think it’s the best at separating business logic and making it more maintainable than having state types trapped inside of the component (not quite sure how this would work for projects with Apollo but that’s another story lol).