{"id":4371,"date":"2023-05-18T15:58:57","date_gmt":"2023-05-18T08:58:57","guid":{"rendered":"https:\/\/www.bagi2info.com\/?p=4371"},"modified":"2023-06-15T13:26:55","modified_gmt":"2023-06-15T06:26:55","slug":"react-native-tutorial-penyimpanan-lokal-expo-sqlite","status":"publish","type":"post","link":"https:\/\/www.bagi2info.com\/en\/react-native-expo-sqlite-local-storage-tutorial\/","title":{"rendered":"React Native Expo SQLite local storage tutorial"},"content":{"rendered":"\r\n<p>In this post, we&#8217;ll look at how to use SQLite to store and persist data locally in our React Native and Expo apps. SQLite is supported by practically all mobile devices. To access it, we must execute SQL queries; however, the data provided is in the form of javascript arrays and objects. To show how to run queries and change React states, we will do CRUD operations.\r\nThe following aspects will be discussed in this post, and all code will be written in the app.js file for convenience and demonstration purposes:<\/p>\r\n\r\n\r\n\r\n<p>Packages<br>Imports and Connection<br>Initialization and UI<br>Operations<br>Read<br>Create<br>Update<br>Delete<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code lang=\"jsx\" class=\"language-jsx line-numbers\">import React from 'react';\r\nimport {\r\n  View,\r\n  Text,\r\n  TouchableOpacity,\r\n  ScrollView,\r\n  StyleSheet,\r\n  SafeAreaView,\r\n  Platform,\r\n} from 'react-native';\r\n\r\nimport Constants from 'expo-constants';\r\nimport * as SQLite from 'expo-sqlite';\r\n\r\nconst db = SQLite.openDatabase('db.testDb'); \/\/ returns Database object\r\n\r\nclass App extends React.Component {\r\n  constructor(props) {\r\n    super(props);\r\n    this.state = {\r\n      data: null,\r\n    };\r\n\r\n    if (Platform.OS != 'web') {\r\n      \/\/ Check if the items table exists if not create it\r\n      db.transaction((tx) => {\r\n        tx.executeSql(\r\n          'CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT, count INT)'\r\n        );\r\n      });\r\n\r\n      this.fetchData(); \/\/ ignore it for now\r\n    }\r\n  }\r\n  \/\/ event handler for new item creation\r\n  newItem = () => {\r\n    db.transaction((tx) => {\r\n      tx.executeSql(\r\n        'INSERT INTO items (text, count) values (?, ?)',\r\n        ['gibberish', 0],\r\n        (txObj, resultSet) =>\r\n          this.setState({\r\n            data: this.state.data.concat({\r\n              id: resultSet.insertId,\r\n              text: 'gibberish',\r\n              count: 0,\r\n            }),\r\n          }),\r\n        (txObj, error) => console.log('Error', error)\r\n      );\r\n    });\r\n  };\r\n  increment = (id) => {\r\n    db.transaction((tx) => {\r\n      tx.executeSql(\r\n        'UPDATE items SET count = count + 1 WHERE id = ?',\r\n        [id],\r\n        (txObj, resultSet) => {\r\n          if (resultSet.rowsAffected > 0) {\r\n            let newList = this.state.data.map((data) => {\r\n              if (data.id === id) return { ...data, count: data.count + 1 };\r\n              else return data;\r\n            });\r\n            this.setState({ data: newList });\r\n          }\r\n        }\r\n      );\r\n    });\r\n  };\r\n  delete = (id) => {\r\n    db.transaction((tx) => {\r\n      tx.executeSql(\r\n        'DELETE FROM items WHERE id = ? ',\r\n        [id],\r\n        (txObj, resultSet) => {\r\n          if (resultSet.rowsAffected > 0) {\r\n            let newList = this.state.data.filter((data) => {\r\n              if (data.id === id) return false;\r\n              else return true;\r\n            });\r\n            this.setState({ data: newList });\r\n          }\r\n        }\r\n      );\r\n    });\r\n  };\r\n  fetchData = () => {\r\n    db.transaction((tx) => {\r\n      \/\/ sending 4 arguments in executeSql\r\n      tx.executeSql(\r\n        'SELECT * FROM items',\r\n        null, \/\/ passing sql query and parameters:null\r\n        \/\/ success callback which sends two things Transaction object and ResultSet Object\r\n        (txObj, { rows: { _array } }) => this.setState({ data: _array }),\r\n        \/\/ failure callback which sends two things Transaction object and Error\r\n        (txObj, error) => console.log('Error ', error)\r\n      ); \/\/ end executeSQL\r\n    }); \/\/ end transaction\r\n  };\r\n\r\n  render() {\r\n    return (\r\n      &lt;SafeAreaView style={Style.main}>\r\n        &lt;Text style={Style.heading}>Add Random Name with Counts&lt;\/Text>\r\n\r\n        {Platform.OS === 'web' ? (\r\n          &lt;View\r\n            style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>\r\n            &lt;Text style={Style.heading}>\r\n              Expo SQlite is not supported on web!\r\n            &lt;\/Text>\r\n          &lt;\/View>\r\n        ) : (\r\n          &lt;>\r\n            &lt;TouchableOpacity onPress={this.newItem} style={Style.green}>\r\n              &lt;Text style={Style.white}>Add New Item&lt;\/Text>\r\n            &lt;\/TouchableOpacity>\r\n\r\n            &lt;ScrollView style={Style.widthfull}>\r\n              {this.state.data &amp;&amp;\r\n                this.state.data.map((data) => (\r\n                  &lt;View key={data.id} style={Style.list}>\r\n                    &lt;Text>\r\n                      {data.text} - {data.count}\r\n                    &lt;\/Text>\r\n                    &lt;View style={Style.list}>\r\n                      &lt;TouchableOpacity onPress={() => this.increment(data.id)}>\r\n                        &lt;Text style={Style.boldGreen}> + &lt;\/Text>\r\n                      &lt;\/TouchableOpacity>\r\n                      &lt;TouchableOpacity onPress={() => this.delete(data.id)}>\r\n                        &lt;Text style={Style.boldRed}> DEL &lt;\/Text>\r\n                      &lt;\/TouchableOpacity>\r\n                    &lt;\/View>\r\n                  &lt;\/View>\r\n                ))}\r\n            &lt;\/ScrollView>\r\n          &lt;\/>\r\n        )}\r\n      &lt;\/SafeAreaView>\r\n    );\r\n  }\r\n}\r\nexport default App;\r\n\r\nconst Style = StyleSheet.create({\r\n  main: {\r\n    backgroundColor: '#fff',\r\n    flex: 1,\r\n    paddingTop: Constants.statusBarHeight,\r\n    padding: 20,\r\n  },\r\n\r\n  white: {\r\n    color: 'white',\r\n  },\r\n  green: {\r\n    backgroundColor: 'green',\r\n    padding: 10,\r\n  },\r\n  boldGreen: {\r\n    backgroundColor: 'green',\r\n    padding: 10,\r\n    borderRadius: 10,\r\n    color: 'white',\r\n    marginRight: 10,\r\n  },\r\n  boldRed: {\r\n    backgroundColor: 'red',\r\n    padding: 10,\r\n    borderRadius: 10,\r\n    color: 'white',\r\n  },\r\n  heading: {\r\n    fontSize: 20,\r\n    fontWeight: 'bold',\r\n    textAlign: 'center',\r\n    paddingVertical: 40,\r\n  },\r\n  list: {\r\n    flexDirection: 'row',\r\n    justifyContent: 'space-between',\r\n    alignItems: 'center',\r\n    borderBottomWidth: 1,\r\n    borderBottomColor: '#ccc',\r\n  },\r\n  widthfull: {\r\n    flex: 1,\r\n  },\r\n});\r\n<\/code><\/pre>\r\n\r\n\r\n\r\n<p><\/p>\r\n\r\n\r\n\r\n<p><\/p>\r\n\r\n\r\n\r\n<p>Snack link<\/p>\r\n\r\n\r\n\r\n<p><a href=\"https:\/\/snack.expo.dev\/@rudiahmad\/sqlite-example\">https:\/\/snack.expo.dev\/@rudiahmad\/sqlite-example<\/a><\/p>\r\n\r\n\r\n\r\n<p>Note: testing cannot use web snacks, run the Expo application to do the testing<\/p>\r\n\r\n\r\n\r\n<p><\/p>\r\n\r\n\r\n\r\n<p>Reference:<\/p>\r\n\r\n\r\n\r\n<p>The coding example is taken from the reference below with the improvement of the code so that it runs and added styles because styles are not shared from the original code<\/p>\r\n\r\n\r\n\r\n<p>https:\/\/reactdevstation.github.io\/2020\/04\/04\/sqllite.html<\/p>\r\n\r\n\r\n\r\n<p><\/p>\r\n\r\n","protected":false},"excerpt":{"rendered":"<p>In this post, we&#8217;ll look at how to use SQLite to store and persist data locally in our React Native and Expo apps. SQLite is supported by practically all mobile devices. To access it,&#46;&#46;&#46;<\/p>\n","protected":false},"author":1,"featured_media":4193,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[173],"tags":[79,65,11,150,145,7],"class_list":["post-4371","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-react-native","tag-android","tag-aplikasi-mobile","tag-database","tag-react-native","tag-source-code","tag-sql"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.bagi2info.com\/en\/wp-json\/wp\/v2\/posts\/4371","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bagi2info.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bagi2info.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bagi2info.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bagi2info.com\/en\/wp-json\/wp\/v2\/comments?post=4371"}],"version-history":[{"count":9,"href":"https:\/\/www.bagi2info.com\/en\/wp-json\/wp\/v2\/posts\/4371\/revisions"}],"predecessor-version":[{"id":4396,"href":"https:\/\/www.bagi2info.com\/en\/wp-json\/wp\/v2\/posts\/4371\/revisions\/4396"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.bagi2info.com\/en\/wp-json\/wp\/v2\/media\/4193"}],"wp:attachment":[{"href":"https:\/\/www.bagi2info.com\/en\/wp-json\/wp\/v2\/media?parent=4371"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bagi2info.com\/en\/wp-json\/wp\/v2\/categories?post=4371"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bagi2info.com\/en\/wp-json\/wp\/v2\/tags?post=4371"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}