Quick & Easy MobX Tutorial in ReactNative — Beginner Steps

This is a very simple, quick and easy tutorial on React Native using MobX for you to get started on the go!

First create a simple react native project using the following link
https://reactnative.dev/docs/environment-setup. Yeah beginner’s steps lol!

Now run your simple init react native project. Just to make sure that your project is atleast up and running. Okay so first step is done. We have our another simple react native project. Woohoo!

Now let’s try integrating MobX!

Let’s first get a quick overview of what MobX really is!

MobX is state management library. It means that it handles and manages app state throughout the application.

I have found Redux, ReactHooks and MobX as the most popular state management libraries for React and ReactNative.

To get to know the idea and difference between these follow this link Why we shifted from Redux to MobX (logicwind.com)

Both Redux and MobX does almost the same thing. But MobX is easy 😎.

Advantages:

  • Easy to setup
  • Easy to explain
  • Easy to manage
  • No boiler plate
  • Magical Rendering
  • And yeah all the good stuff

Now’s let get started!

Open your regular code editor. (I personally prefer VSCode and of course with black theme 😜)

Okay so first you need to install two dependencies to get started which are mobx and mobx-react. Use this command npm install mobx mobx-react

And also you will need a DEV dependency npm install --save-dev @babel/plugin-proposal-decorators because MobX works on decorators.

Now in your project you will find a file babel.config.js
In that you will find a key preset. Add below code below this preset key

"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
]
]

In the latest versions of MobX you may also need to add more configurations as given below in the image. You may add it if needed.

module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
['@babel/plugin-transform-flow-strip-types'],
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
["@babel/plugin-proposal-class-properties",
{
"loose": false
}]
]
};

Also you will have to enable Experimental Decorators in your code editor’s setting. But it’s not necessary. It’s just for the red lines that might show up in your code editor

Let’s begin with our regular stuff. Yeah that’s right CODING!

In your project create a file call TodoStore.js
Something like this simple code given below

import React from "react";
import { observable, action, computed, makeObservable } from "mobx";
import AsyncStorage from '@react-native-community/async-storage';

class TodoStore {

@observable idForTodo = 3;

@observable todos = [
{
id: 1,
title: "Todo 1",
completed: false
},
{
id: 2,
title: "Todo 2",
completed: false
},
];

constructor() {
makeObservable(this)
}

@action getData = async () => {
const value = await AsyncStorage.getItem('TODOS')
if (value !== null) {
this.todos = JSON.parse(value)
}
}

@action addTodo = async (todoInput) => {
this.todos.push({
id: this.idForTodo,
title: todoInput.trim(),
completed: false
});
await AsyncStorage.setItem('TODOS', JSON.stringify(this.todos))
this.idForTodo++;
};

@action deleteTodo = async (id) => {
const index = this.todos.findIndex((item) => item.id === id);
this.todos.splice(index, 1);
await AsyncStorage.setItem('TODOS', JSON.stringify(this.todos))
};

@action checkTodo = async (todo) => {
todo.completed = !todo.completed;
const index = this.todos.findIndex((item) => item.id === todo.id);
this.todos.splice(index, 1, todo);
await AsyncStorage.setItem('TODOS', JSON.stringify(this.todos))
};

@action checkAllTodos = async (value = true) => {
this.todos.forEach((todo) => (todo.completed = value));
await AsyncStorage.setItem('TODOS', JSON.stringify(this.todos))
};

@computed get todosCompletedCount() {
return this.todos.filter((todo) => todo.completed).length;
}

@computed get remaining() {
return this.todos.filter((todo) => !todo.completed).length;
}

}

const store = new TodoStore();
export default store;

observable — an element whenever updates it will re-render wherever it is used in the application

action — it allows to create a function in the store which further updates the observable

computed — it is called automatically whenever an observable is updated

Great. We have created our first store! You can now create other stores in similar manner.

Now we have to wrap/bind this store to our application in our App.js as shown below using Provider from mobx-react

import * as React from 'react';
import { Provider } from 'mobx-react';
import TodoStore from './TodoStore';
import Home from './Home';

class App extends React.Component {
render() {
<Provider todoStore={TodoStore} >
<Home />
</Provider>
}
}

Now let’s create a Home.js to get our simple Todo demo up and running using MobX functionality

PS: I have added react-native-swipe-item and react-native-elements just to have good UI/UX and clear idea of functional requirement

import React, { Component } from 'react';
import { View, TextInput, SafeAreaView, StyleSheet, TouchableOpacity } from 'react-native';
import { SwipeItem, SwipeButtonsContainer } from 'react-native-swipe-item';
import { Header, ListItem, Text, Button } from 'react-native-elements';
import AsyncStorage from '@react-native-community/async-storage';
import { inject, observer } from 'mobx-react';

@inject('todoStore')
@observer
export default class Home extends Component {

constructor(props) {
super(props)
this.state = {
text: ''
}
}

componentWillMount() {
const { todoStore } = this.props
todoStore.getData();
}

onChangeText = (text) => {
if (text && !!text) {
this.setState({ text })
}
}

SubmitData = () => {
try {
const { text } = this.state
if (text && !!text) {
this.setState({ text: '' })
const { todoStore } = this.props
todoStore.addTodo(text)
} else {
alert('Please enter todo title!')
}
} catch (error) {
alert('Something went wrong')
}
}

swipeRender = (index) => {
return (
<SwipeButtonsContainer style={styles.swipcercell}>
<TouchableOpacity onPress={() => this.markTodo(index)} >
<Text>Mark</Text>
</TouchableOpacity>
</SwipeButtonsContainer>
);
}

swipeDelete = (index) => {
return (
<SwipeButtonsContainer style={styles.swipcercell}>
<TouchableOpacity onPress={() => this.deleteTodo(index)} >
<Text>Delete</Text>
</TouchableOpacity>
</SwipeButtonsContainer>
);
}

markTodo = (index) => {
const { todoStore } = this.props
todoStore.checkTodo(todoStore.todos[index])
}

deleteTodo = (index) => {
const { todoStore } = this.props
todoStore.deleteTodo(index)
}

render() {
const { todos, todosCompletedCount } = this.props.todoStore
const { text } = this.state

return (
<>
<SafeAreaView style={styles.SafeAreaViewcontainer}>

<Header
centerComponent={{ text: 'MY TODOS', style: { color: '#fff' } }}
/>

<View style={{ margin: 10 }}>
<TextInput
value={text}
placeholder={'Add Todo'}
onChangeText={this.onChangeText}
/>

<View style={styles.buttonrow}>
<Text style={styles.todomaintitle}>todosCompletedCount()</Text>
</View>

<View style={styles.buttonrow}>
<Button
title="Submit"
containerStyle={styles.buttonsubmit}
onPress={this.SubmitData}
/>
</View>

{todos.length > 0 &&
<>
<View>
<Text style={styles.todomaintitle}>My Todos</Text>
</View>
{todos.map((data, index) => {
return (
<SwipeItem
key={index}
style={styles.button}
swipeContainerStyle={styles.swipeContentContainerStyle}
leftButtons={() => this.swipeRender(index)}
rightButtons={() => this.swipeDelete(index)}
>
<ListItem
titleStyle={{ color: data.completed ? 'green' : 'red' }}
style={styles.listiem}
title={data.title}
/>
</SwipeItem>

)
})}
</>
}
</View>
</SafeAreaView>
</>
);
}
}

const styles = StyleSheet.create({
SafeAreaViewcontainer: { flex: 1, width: '100%' },
button: {
alignItems: 'center',
justifyContent: 'center',
alignSelf: 'center',
height: 55,
marginTop: 10,
backgroundColor: 'white',
},
swipcercell: {
alignSelf: 'center',
aspectRatio: 1,
flexDirection: 'column',
padding: 10,
},
swipeContentContainerStyle: {
borderRadius: 10,
borderColor: 'black',
borderWidth: 1,

},
listiem: {
backgroundColor: 'white',
borderColor: 'transparent', borderRadius: 10, width: '98%', paddingLeft: 10
},
buttonsubmit: {
width: '100%',
flex: 1,
justifyContent: 'space-between',
marginLeft: 10,
marginRight: 10,
marginTop: 20,
marginBottom: 20,
},
buttonrow: {
flexDirection: 'row'
},
todomaintitle: { fontSize: 20, fontWeight: 'bold', marginLeft: 10 }
});

inject — it will get the whole store in our Home Component

observer — it will allow our Home component to listen to the changes/updates made into the observableof our TodoStore

As you can see I have render todosCompletedCount() in Text component. This is a @computed function of our TodoStore. It will be called initially and whenever a observable is updated

Voila! We are done! That's all folks!
Yeah it's that simple and easy!
Hope you find it useful!
Thanks for reading!

Originally published at http://blog.logicwind.com on February 2, 2021.

--

--

--

We craft digital products for your business growth. Development | Marketing | Branding | Strategic Partnership

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Why I Use Custom Data Attributes for Selecting Elements in JavaScript

Brief Explain about Basics of RxJava (PART — 2)

8 React Libraries That I’d Like To Introduce To You

Laravel Unique Validation Rules Examples

This Keyword in JavaScript

ReactJS QR Code Scanner

Getting Deeper Insight into DHTMLX JavaScript Diagram Editor

Top 10 JavaScript Interview Questions — Part -2

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Logicwind

Logicwind

We craft digital products for your business growth. Development | Marketing | Branding | Strategic Partnership

More from Medium

Component Life Cycle in React Native

Camera feature using React native

Text strings must be rendered within a <Text> component. ReactNative

Fastlane with React Native — Part-1