Redux and global state vs. local state


(Alexander Whillas) #1

I’ve been working with Redux to manage component state and have found it’s a lot more work than just using this.state. A lot for the time there doesn’t seem to be much of a payoff except when you want to share that state with other components. The zealots of the “One true flow” seem to never make exceptions: Everything must got through the Action > Reducer > Component cycle which is laborious to implement (especially of your doing testing).

I’ve come to see Redux as global state and this.state as local state, as one sees global and local variables, but nobody seems to talk about this or come up with rules-of-thumb as to weather using an mix of both as permissible and if it is when is it OK?

For example i’m finding that with controlled forms, in which the state is never needed outside the component until after it is submitted, its faster and easier to just use local state and update Redux after the submitted data has changed something on the server.

My rule of thumb is now: If the data is not referenced outside the component then use local state. If its share between components use global (Redux).

Is there some rationale as to why this would be a misnomer? Arguments for or against?


(Mikayel) #2

You can consider Context as an option too, read more here Vanilla React without Redux or Flux


(Alexander Whillas) #3

Or i could just use local state.


(Mikayel) #4

It depends of your app, but I am not seeing any reason not to use local state.


(Guy Ellis) #5

@awhillas what do you do if you’re using the same form to both create and edit your data. The create case is simple and you’ve explained that. In the edit scenario, do you pass your existing data to the component as props and then copy it to state and then pass to redux on save?


(Egauci) #6

In my opinion it’s perfectly fine to use local state if nothing outside that component has any interest in it. Your example of form data before submit fits.


(Alexander Whillas) #7

Yeah, pass it in as props. This is how the Redux data is presented to the component anyway. In fact you can still choose to do ether. Where the data comes from doesn’t have to be the same as where it goes. Changing ether doesn’t affect the mechanics of the controlled component form. The internals of which follow the OOP principle of encapsulation.

You might load the data from Redux if you have already loaded it previously or you might fetch() it from the server. In ether case you’d probably want to send it to the server onSubmit and then update your Redux when you get a confirmation back that it worked. Once it leaves the form component it doesn’t care what happens to the data (if you get a server error then pass that in as props with the data).


(Jeremy Judeaux) #8

I tend to prefer the Everything should go through “Action > Reducer > Component” (or I would say the “Event > Reduce > Render”). At least, I think you didn’t give an example of a situation where this should not happen. I prefer this for consistency in the code base.

Now, I’m not in favor of the “One single global state”. It is interesting to have some components which behaves like a black-box from the application point of view:

  • easier to duplicate (you can have two instances without worrying where you’ll put the “collapsed” state in the global store)
  • easier to share, between your projects or publish on npm
  • easier to break the application’s complexity in order to improve comprehension and maintenance

Two more points:

It’s interesting to make a comparison between your form and how React handles the INPUT element. React provides the ability to handle the INPUT’s state in a global store with value and onChange, or to let the INPUT element handle its own state, only using defaultValue, and eventually onChange or ref.value to get the final value. You can absolutely do something similar with your form.

Also I started by saying that I prefer everything through Action>Reducer>Component. You don’t need redux to do that. You can have a pure reducer function alongside your component, a simple dispatch method in your component, a few more methods to dispatch the events, and that’s all:

dispatch(event) {
  this.setState(reducer(event, this.state));
}
incrementCounter() {
  this.dispatch({type:INCREMENT_COUNTER});
}

(Develerltd) #9

Personally, I’ve really wanted to use a Flux methodology for creating applications, but I generally find that there are other methods that work better for me, with less unnecessary going through the motions.

Pretty much 95% of my react app code is managed solely by the individual components, with either a middleware style component wrapping sub-component routes (ie to handle a particular product id or such), or using a global data-store with key/value and add/clear listeners when they change. The event handling happens entirely inside the individual components, I just break up the components into a controller and view - with the view merely rendering the props, and the controller doing all ajax and mount/unmount event functionality


(Ryanirilli) #10

You are absolutely correct, I use local state to keep track of form data, boolean values for conditional rendering, and anything else the component might need to do its thing. This is especially true if you have a prop on your component from the store, and you allow the user to edit that prop. if you set it on the state in getInitialState() { return { user: this.props.user} } , cancelling the edit is as easy as calling this.setState(this.getInitialState()) (assuming the user prop is an immutable object)

However, the issue is, if the component gets unmounted for whatever reason (route change usually) then you lose the data.

So yes, I think it’s fine to use state, it’s there for a reason, however, think about your use case and be deliberate about the data that you’re storing because the user might leave that view and when they come back, it would be nice to still have the same state and orientation.

Another use case for state versus the Redux store is that you don’t have to clean up the store to get rid of data you don’t need. For example, a login form with username and password fields. you really shouldn’t keep that information in the store, it’s just a means to authenticate the user and retrieve an auth token. I just set those values on the state of my login component and they are lost as soon as the user successfully logs in and redirects to the app component.

Usually though, you will find keeping the overall state of your application should live in the store. keeping track of the UI state and user data gives you a lot more control over the user experience as a whole. The beauty is Redux makes it trivial to move component state into the store.


(Mark Erikson) #11

It is absolutely fine to mix local/component state and Redux state. Mix it up whatever way works best for you. The Redux FAQ actually addresses this question: http://redux.js.org/docs/FAQ.html#organizing-state-only-redux-state .


(Gcazaciuc) #12

Just wanted to bring up, if keeping local state isn’t your thing, a new approach for keeping ui state into the redux store can be found here: [redux-fractal] ( https://github.com/gcazaciuc/redux-fractal )


(Marc Cyr) #13

You got lots of responses, so I didn’t take the time to read through all of them. Apologies if this was said before:

I am completely in line with your thinking and that is the approach that has been taken by my team to build a large application. From day one, I said this is the rule of thumb: If the other components care about the state, then it is app-level state. Otherwise, keep it local as component state.

I would think most Redux apps would have a combination of components and containers (components being unconnected, containers being connected to Redux state).

You’re on the right track. It keeps things from being over-engineered when it’s better to keep things simple.


(Trần Văn Hoàng) #14

When i login success, isLogin state equal true then page when route to home page. but when refresh page again, isLogin state equal false. How i can get old state when i refresh page. i using redux store to save states. thanks


(Dschinkel) #15

I don’t care what the Redux docs say, I don’t see any reason to update state using this.state = or setState() if using React-redux. I’m sorry but consistency is key and also consolidating all logic outside your views is critical. Views should not have logic PERIOD. Whether that means you move your handlers into mapDispatchToProps or always keep state but form and app data in the store, it’s in one place, you don’t have state transitions going on that could muck up things outside your actions and reducers that are already keeping the flow predictable.

And for testing, there’s no reason to keep any state updates going on in your dumb components. Updating state is behavior, I’m sorry and that belongs either in a separate connected component file where you put everything else such as your lifecycle methods, mapStateToProps, etc. That should go in there too. It keeps things seperate, easy to maintain, testable, and decoupled. Your views should be completely dumb, I disagree…move any handlers, keep updating of states via actions, and even local form data, keep that out of your dumb components and I’d say still manage them via your state tree.


(Mukul Jain) #16

This link should be useful, in short, we yes we can have local states as long as they don’t have any special purpose for the app.


(Søren Høyer Kristensen) #17

Another option would be to structure your projects similar to this: https://medium.com/@alexmngn/how-to-use-redux-on-highly-scalable-javascript-applications-4e4b8cb5ef38

But what I’d recommend the most is MobX State Tree. Took me 15 days to realize that I needed to give it a shot (felt a bit intimidated and got turned-off at first, due to the new syntax you have to learn, but it really is not much, once you start actually writing code and you definitely quickly learn to appreciate the benefits that comes with it). Once I stopped hating, and started coding, it only took me 1 full day to learn the basics and some code working, 5 days to rewrite a medium complex app and after little more than a week I now feel completely comfortable with it. My project got more consistent, I’m more productive and it just makes so much sense now. In many ways I now feel my code is much cleaner now, even though Redux is pure js and MST brings a little of its own flavor. Be sure to watch the talks with Michel, and you’ll understand why learning MST will be great is you wish to ditch local state in react. Also make sure to read up on one of it’s concepts: volatile state.


(Søren Høyer Kristensen) #18

So good to hear I’m not the only one disagreeing with the general and official consensus about keeping ephemeral state in react’s local state and only application state in redux. If you build an app structure to support Redux, why not stick to it and be consistent. With the right app structure it is not THAT much extra work, compared to the benefits of being able to inspect the entire application state from redux dev tools at any given point in time + the ease of preloading the entire ui or parts from localstorage or configuration files.

What I love about Redux is that you still get to write javascript. That makes the additional boilerplate totally worth it. Redux really has very little concept you need to understand, and once you do, it doesn’t get much simpler than that.

Personally I think that Redux’ biggest problems is that it can be so tricky to decide what goes in Redux and what not - there’ll always be alot of pros / cons and inconsistencies when different devs should need to decide such a thing. The official recommendation and “best practices” is a big mystery to me.


(Sigmoid) #19

This is something I am also thinking a lot about. I really like the approach in “How to use Redux on highly scalable javascript applications?” - though I ended up commenting there about the question of “logic in reducers”. I think certain kinds of logic most definitely belong in reducers…

Anyway… The core feature of Redux is “time travel”. Anything outside the global state cannot be rewound, or tracked. So I’d feel bad putting anything important outside Redux. I do put managing stylistic animations outside, for example. Form validation, I’d rather not.

I do feel there is a lot of overhead in having to wrap each component. My code is a criss-cross between views and containers. Views include containers, containers include views. I tried skimping on it, and ended up with ridiculous mammoth containers, and traditional props-passing React spaghetti inside. (Spaghetti bad! Oonga no like!)

So… I guess both with React and Redux, we’ve made the choice to write more code, as a tradeoff in exchange for having to debug less. Something for something. :smiley: