setState vs Mobx

Should I use setState or not to modify my state

Rui Vilela
Beamery Hacking Talent
4 min readJun 12, 2018

--

There is a common discussion that happens when you’re building react applications. Should I use setState or not to modify my state. There are definitely situations where you could say using setState is okay.

It’s always hard to predict cases where things may go wrong. What is considered a good or bad use case can quickly become something subjective. setState is quite complex although quite overlooked. It seems like a quick and simple solution, that will haunt you in the future. 😔

To further understand why, let’s take a look what react’s documentation has to say about it.

Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately. — reactjs.org

The main issue I have with this explanation is the fact that it doesn’t change the state immediately. This means our state changes aren’t synchronous, which is the main reason why reducers in Redux only handle synchronous code, so that when you want to change the state it will actually happen in that action and not in a later one.

The solution purposed to fix setState, is not ideal either. You’ll have to force a re-rendering of the component using this.forceUpdate(). This gets quite awkward because it leads to unnecessary renders and feels more like a hack to something than a proper solution. Even reactjs.org documentation tells you to avoid using it, “Normally you should try to avoid all uses of forceUpdate()

Why can’t we use Redux all the time?

Using Redux may seem the natural successor of setState, and it is for most cases. The problem of Redux is it’s boilerplate code which needs to be implemented every time we need to manipulate certain state. Although the boilerplate is also the reason why it is great, (because the code becomes predictable and handles complex business logic), when we just want to simply change state, unrelated to business logic, (change colours, tick-untick boxes, etc…) then creating a state container for each time we want to use that component seems like an overcomplicated solution for something that should be simple.

That’s why you should use Mobx ☝️

Mobx is a library for state manipulation. The fact that it changes the state synchronously solves the problem of setState, and not being opinionated gives you an alternative to Redux when it feels like you’re just overcomplicated it.

How we implement this ? 🤔

For this example let’s imagine an UI component that changes text when you click on it.

class MyComponent extends Component {
constructor (props) {
super(props);
this.text = 'click me';
}
render () {
return (
<div>
{this.text}
<div>
)
}
}

Our code for starter should like the example above, so basically we didn’t add any functionality it will just display our text. Let’s add our clicking functionality.

class MyComponent extends Component {
constructor (props) {
super(props);
this.text = 'click me';
}
changeText () {
// you setState would be here normally
}
render () {
return (
<div onClick={this.changeText}>
{this.text}
<div>
)
}
}

Now let’s implement Mobx so we do not need to use setState 🙌.

First we need to wrap our Component with the observer function. What this does is telling our class that it should observe any observable we define. To simplify let’s export our Component with the observer wrapper, and deal with the mobx logic in a different file. So our component file export would look like this:

export default observer(MyComponent)

Now let’s see how our code would look in this new file.

import { action, decorate, observable } from ‘mobx’;import MyComponent from ‘./component’;decorate(
MyComponent,
{
text: observable,
changeText: action
}
);
export default MyComponent;

A lot of stuff is happening here so no worries I’ll break it down for you.

The decorate function, takes two parameters. The first parameter is the Component wrapped with the observer function. The second parameter is an object. This object tells us what the observer class should look at, so basically how it should interpret it.

So by defining text is an observable, we are basically saying that this.text will be transformed into an observable so any changes to it will be listened by the observer.

A similar logic applies to defining changeText as being the action, means that this.changeText will be interpret as the place the state mutation occurs.

So in order to actually change text we just need to finalise our component, by changing this.text inside our action.

class MyComponent extends Component {
constructor (props) {
super(props);
this.text = 'click me';
}
changeText () {
this.text = 'just changed the text'
}
render () {
return (
<div onClick={this.changeText}>
{this.text}
<div>
)
}
}

--

--