Redux or MobX -
Β
What Should I Pick For My React App?
Outline
- What Problem Are We Trying To Solve
- What Is Redux
- What Is MobX
- Showcase
- Comparison
- Conclusion / Q&A
What Problem Are We Trying To Solve
const UserCard = ({ user }) => (
<div>
<p> Name: {user.name} </p>
<p> Age: {user.age} </p>
</div>
)
class UserPage extends Component {
userData = {}
componentDidMount() {
// Fetch information of current user
fetch('https://restful-api-endpoint.com/v1/user/30678')
.then(res => res.json())
.then(json => this.setState({ userData: json }))
}
render() {
return (
<>
<UserCard user={this.state.userData} />
</>
)
}
}
A simple but usual case:
Developing a SPA and handle routes by react router.
class AboutMePage extends Component {
render() {
const { userData } = this.state
return (
<>
Welcome {userData.name}! Check your information below.
<UserCard user={userData} />
</>
)
}
}
const Sidebar = ({ user }) => (
<>
<Header user={user} />
<Menu>
<MenuItem>Homepage</MenuItem>
<MenuItem>About Me</MenuItem>
<MenuItem>Posts</MenuItem>
</Menu>
</>
)
const Header = ({ user }) => (
<UserCard user={userData} />
)
Imagine that we have to display UserCard UI with the shared data otherwhere.
So, what can we do before
v16.3 released?
class AppRoot extends Component {
userData = {}
componentDidMount() {
// Fetch information of current user
fetch('https://restful-api-endpoint.com/v1/user/30678')
.then(res => res.json())
.then(json => this.setState({ userData: json }))
}
render() {
const { userData } = this.state
return (
<BrowserRouter>
<Sidebar user={userData} />
<Switch>
<Route
path="/about"
render={routeProps => <AboutMePage {...routeProps} user={userData} />}
/>
<Route
path="/user"
render={routeProps => <UserPage {...routeProps} user={userData} />}
/>
</Switch>
</Router>
)
}
}
There is a simple and intuitive solution.
Prop Drilling
https://www.carlrippon.com/playing-with-the-context-api-in-react-16-3/
There're still some problems
Context API can not solve
- Cross-Cutting Concerns
- Asynchronous Calls and Side Effects
- Predictable Dataflow
What Is Redux
Redux Highlight
- A state management solution
- Single Source of Truth (SSOT)
- Inspired by flux and influenced by FP
- Popular and Well-developed ecosystem
When to Use?
- When you want to avoid prop drilling.
- When some states should be shared between more than one components.
- When you want to manipulate global or top-level component. (e.g. Notification, Toast, Modal, Tooltips.)
- When you want to write applications that behave consistently.
- When the UI and business logic youΒ faced is too complex to handle currently.
https://itnext.io/integrating-semantic-ui-modal-with-redux-4df36abb755c
What Is MobX
MobX Highlight
- A least obtrusive libraries you can use for state management.
- Make state managements simple by Functional Reactive Programming (FRP) paradigm.
- No need to normalize your data anymore.
- Be Reactive!
- Simple.
Overview
Core Concepts
- Observable State
- Computed values
- Reactions
- Actions
Observable State
import { observable } from 'mobx'
const state = {
userData: {},
}
export default observable(state)
import { observer } from 'mobx-react'
import UserCard from '../components/UserCard'
import state from './state'
const Comp = () => (
<>
<UserCard user={state.data} />
</>
)
export default observer(Comp)
Computed Values
class TodoList {
@observable todos = []
@computed get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length
}
}
import { decorate, observable } from "mobx"
class TodoList {
todos = []
get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length
}
}
decorate(TodoList, {
todos: observable,
unfinishedTodoCount: computed
})
Reactions
@observer
class TodoListPage extends Component {
const { store } = this.props
render() {
return (
<div>
<ul>
{
store.todos.map(todo => <TodoItem todo={todo} key={todo.id} />)
}
</ul>
Tasks left: {store.todos.unfinishedTodoCount}
</div>
)
}
}
const TodoItem = observer(({ todo }) =>
<li>
<input
type="checkbox"
checked={todo.finished}
onClick={() => todo.finished = !todo.finished}
/>
{todo.title}
</li>
)
const store = new TodoList()
ReactDOM.render(<TodoListPage store={store} />, document.getElementById('app'))
Actions
Unlike many flux frameworks, MobX is unopinionated about how user events should be handled.
-
This can be done in a Flux like manner.
-
Or by processing events using RxJS.
-
Or by simply handling events in the most straightforward way possible, as demonstrated in the above onClick handler.
There is no technical need for firing events, calling a dispatcher or what more. A React component in the end is nothing more than a fancy representation of your state. A derivation that will be managed by MobX.
import { action, observable } from 'mobx'
const state = {
userData: {},
getUserData: action(function() {
fetch('https://restful-api-endpoint.com/v1/user/30678')
.then(res => {
this.userData = res
})
})
}
export default observable(state)
Showcase
Comparison
Redux
Mobx
-
Single store (SSOT)
-
FP paradigm
-
Pure
-
Explicit update logic and dataflow
-
More boilerplate
-
Normalized state
-
Multiple stores
-
RFP paradigms
-
Impure
-
Implicit update logic and dataflow
-
Less boilerplate
-
Denormalized state
Redux | MobX | |
---|---|---|
Easy to learn | π | πππ |
Scalability | πππ | ππ |
Testability | πππ | π |
Predictability | πππ | ππ |
Line of code | π | πππ |
Managing Asynchronous Calls | β | β |
Handling Side Effects | β | β |
βSeparation of Concerns (SoC) | β | β |
Conclusion
Q&A
Redux or MobX - What Should I Pick For My React App?
By hinx
Redux or MobX - What Should I Pick For My React App?
- 821