├── .gitignore ├── .watchmanconfig ├── App.js ├── README.md ├── app.json ├── app ├── components │ └── TaskListScreen.js └── mobx │ └── TaskListStore.js ├── assets ├── icon.png └── splash.png ├── babel.config.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | *.jks 5 | *.p12 6 | *.key 7 | *.mobileprovision 8 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | Platform, 4 | StyleSheet, 5 | Text, 6 | View 7 | } from 'react-native'; 8 | 9 | import TaskListScreen from './app/components/TaskListScreen' 10 | 11 | export default class App extends Component { 12 | render() { 13 | return () 14 | } 15 | } 16 | 17 | const styles = StyleSheet.create({ 18 | container: { 19 | flex: 1, 20 | justifyContent: 'center', 21 | alignItems: 'center', 22 | backgroundColor: '#F5FCFF', 23 | }, 24 | welcome: { 25 | fontSize: 20, 26 | textAlign: 'center', 27 | margin: 10, 28 | }, 29 | instructions: { 30 | textAlign: 'center', 31 | color: '#333333', 32 | marginBottom: 5, 33 | }, 34 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-expo-mobx 2 | React Native with Expo and MobX 3 | 4 | ## Step 1: Install packages: 5 | ``` 6 | npm install --save mobx mobx-react 7 | ``` 8 | ## Step 2: Install dev package and config it: 9 | 10 | ``` 11 | npm install --save-dev @babel/plugin-proposal-decorators 12 | ``` 13 | 14 | We need to add this plugin to `babel.config.js` like bellow: 15 | 16 | ``` 17 | module.exports = function(api) { 18 | api.cache(true); 19 | return { 20 | presets: ['babel-preset-expo'], 21 | plugins: [ 22 | [ 23 | "@babel/plugin-proposal-decorators", 24 | { 25 | "legacy": true 26 | } 27 | ] 28 | ] 29 | }; 30 | }; 31 | 32 | ``` 33 | 34 | ## Step 3: Create store and use it: 35 | 36 | **TaskListStore.js:** 37 | 38 | 39 | ``` 40 | 41 | import { observable, action } from 'mobx' 42 | 43 | class TaskListStore { 44 | 45 | @observable list = [ 46 | { title: 'Go to the School', isFinished: true }, 47 | { title: 'Prepare tasks for today', isFinished: false }, 48 | { title: 'Team meeting', isFinished: false }, 49 | { title: 'Commit tasks changed', isFinished: false } 50 | ] 51 | 52 | @action finishItem (index) { 53 | const copiedList = this.list.slice() 54 | const isFinished = copiedList[index].isFinished 55 | if (isFinished) return 56 | 57 | copiedList[index].isFinished = true 58 | this.list = copiedList // update store by re-assigning 59 | } 60 | 61 | @action deleteItem (index) { 62 | this.list = this.list.filter((item, i) => i != index) 63 | } 64 | } 65 | 66 | const store = new TaskListStore() 67 | export default store 68 | 69 | 70 | ``` 71 | 72 | **TaskListScreen.js:** 73 | 74 | ``` 75 | import React, { Component } from 'react' 76 | import { 77 | StyleSheet, 78 | Text, 79 | TouchableOpacity, 80 | FlatList, 81 | View 82 | } from 'react-native' 83 | 84 | import taskListStore from './../mobx/TaskListStore' 85 | import { observer } from 'mobx-react/native' 86 | 87 | @observer 88 | export default class TaskListScreen extends Component { 89 | 90 | renderItem = ({ item, index }) => { 91 | return ( 92 | 93 | 94 | taskListStore.finishItem(index)}> 95 | {(item.isFinished) ? `✅` : `🕘`} 96 | 97 | 98 | 99 | {item.title} 100 | 101 | 102 | taskListStore.deleteItem(index)}> 103 | {`❌`} 104 | 105 | 106 | 107 | ) 108 | } 109 | 110 | render() { 111 | const list = taskListStore.list.slice() // don't forget copy the list from store 112 | 113 | return ( 114 | `${index}`} 119 | renderItem={this.renderItem} 120 | /> 121 | ) 122 | } 123 | } 124 | 125 | 126 | 127 | ``` 128 | 129 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "HelloExpo", 4 | "slug": "HelloExpo", 5 | "privacy": "public", 6 | "sdkVersion": "31.0.0", 7 | "platforms": [ 8 | "ios", 9 | "android" 10 | ], 11 | "version": "1.0.0", 12 | "orientation": "portrait", 13 | "icon": "./assets/icon.png", 14 | "splash": { 15 | "image": "./assets/splash.png", 16 | "resizeMode": "contain", 17 | "backgroundColor": "#ffffff" 18 | }, 19 | "updates": { 20 | "fallbackToCacheTimeout": 0 21 | }, 22 | "assetBundlePatterns": [ 23 | "**/*" 24 | ], 25 | "ios": { 26 | "supportsTablet": true 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /app/components/TaskListScreen.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { 3 | StyleSheet, 4 | Text, 5 | TouchableOpacity, 6 | FlatList, 7 | View 8 | } from 'react-native' 9 | 10 | import taskListStore from './../mobx/TaskListStore' 11 | import { observer } from 'mobx-react/native' 12 | 13 | @observer 14 | export default class TaskListScreen extends Component { 15 | 16 | renderItem = ({ item, index }) => { 17 | return ( 18 | 19 | 20 | taskListStore.finishItem(index)}> 21 | {(item.isFinished) ? `✅` : `🕘`} 22 | 23 | 24 | 25 | {item.title} 26 | 27 | 28 | taskListStore.deleteItem(index)}> 29 | {`❌`} 30 | 31 | 32 | 33 | ) 34 | } 35 | 36 | render() { 37 | const list = taskListStore.list.slice() // don't forget copy the list from store 38 | 39 | return ( 40 | `${index}`} 45 | renderItem={this.renderItem} 46 | /> 47 | ) 48 | } 49 | } 50 | 51 | const styles = StyleSheet.create({ 52 | container: { 53 | flex: 1, 54 | backgroundColor: '#E1F5FE', 55 | paddingTop: 20 56 | }, 57 | itemContainer: { 58 | flexDirection: 'row', 59 | alignItems: 'center', 60 | backgroundColor: 'white', 61 | marginHorizontal: 10, 62 | marginTop: 10, 63 | paddingHorizontal: 10, 64 | paddingVertical: 15, 65 | borderRadius: 5, 66 | borderColor: 'gray', 67 | shadowOffset: { width: 0, height: 1 }, 68 | shadowOpacity: 0.2, 69 | shadowColor: 'gray', 70 | elevation: 2 71 | } 72 | }) -------------------------------------------------------------------------------- /app/mobx/TaskListStore.js: -------------------------------------------------------------------------------- 1 | import { observable, action } from 'mobx' 2 | 3 | class TaskListStore { 4 | 5 | @observable list = [ 6 | { title: 'Go to the School', isFinished: true }, 7 | { title: 'Prepare tasks for today', isFinished: false }, 8 | { title: 'Team meeting', isFinished: false }, 9 | { title: 'Commit tasks changed', isFinished: false } 10 | ] 11 | 12 | @action finishItem (index) { 13 | const copiedList = this.list.slice() 14 | const isFinished = copiedList[index].isFinished 15 | if (isFinished) return 16 | 17 | copiedList[index].isFinished = true 18 | this.list = copiedList // update store by re-assigning 19 | } 20 | 21 | @action deleteItem (index) { 22 | this.list = this.list.filter((item, i) => i != index) 23 | } 24 | } 25 | 26 | const store = new TaskListStore() 27 | export default store -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeMasterChef/react-native-expo-mobx/385ca2e29f68d699f3f00cfc8f558ae9a421e5f6/assets/icon.png -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeMasterChef/react-native-expo-mobx/385ca2e29f68d699f3f00cfc8f558ae9a421e5f6/assets/splash.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | plugins: [ 6 | [ 7 | "@babel/plugin-proposal-decorators", 8 | { 9 | "legacy": true 10 | } 11 | ] 12 | ] 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "node_modules/expo/AppEntry.js", 3 | "scripts": { 4 | "start": "expo start", 5 | "android": "expo start --android", 6 | "ios": "expo start --ios", 7 | "eject": "expo eject" 8 | }, 9 | "dependencies": { 10 | "expo": "^31.0.2", 11 | "mobx": "^5.6.0", 12 | "mobx-react": "^5.4.2", 13 | "react": "16.5.0", 14 | "react-native": "https://github.com/expo/react-native/archive/sdk-31.0.0.tar.gz" 15 | }, 16 | "devDependencies": { 17 | "@babel/plugin-proposal-decorators": "^7.1.6", 18 | "babel-preset-expo": "^5.0.0", 19 | "babel-preset-react-native-stage-0": "^1.0.1" 20 | }, 21 | "private": true 22 | } 23 | --------------------------------------------------------------------------------