Constructing offline React Native apps with AsyncStorage
Printed on Aug 18, 2019
•
34 min learn
•
As builders, we love exploring ideas and mechanisms whereas working with a brand new framework. React Native as a cross-platform growth framework has come fairly far by way of a mature framework since I began enjoying round with it after which utilizing it for its objective. Understanding the basics when studying it’s one thing very useful, and I contemplate, necessary.
Thus, making use of fundamental fundamentals of React Native data, on this tutorial, I’m going to stroll you thru the best way to construct a todo record software utilizing an offline storage performance. This storage performance is offered by a local module in React Native, known as AsyncStorage
.
Within the journey of constructing this software, you’ll use a UI element library generally known as Native Base, which is without doubt one of the hottest libraries to construct consumer interfaces amongst React Native builders. Out of the field, this library accelerates the event course of by offering pre-defined UI parts that may both be used as they’re out there or customise them in response to our wants.
What are we constructing?
🔗
The end result from following this tutorial goes to be an entire React Native software that works with realtime offline knowledge from the storage of the gadget.
Desk of Contents
🔗
- Conditions
- Create an Expo app
- Exploring AsyncStorage
- Using AsyncStorage API
- Including Navigation
- Making a Floating Motion Button (FAB)
- Navigating between Two Screens
- Customise the Header Part
- Rendering an inventory of things utilizing FlatList
- Studying Information utilizing AsyncStorage API
- Including a Todolist Merchandise
- Deleting a Todolist Merchandise
- Mark an Merchandise Test or Uncheck on completion
- Passing Information between completely different screens utilizing the navigation
- Show every todo record merchandise
- Bonus Part: Including a Section
- Conclusion
Conditions
🔗
To observe this tutorial, please be sure you have the next put in in your native growth atmosphere and have entry to the providers talked about beneath:
- Node.js (>=
8.x.x
) with npm/yarn put in. - expo-cli (>=
3.0.4
), beforehand generally known as create-react-native-app.
It will likely be greatest in case you use the identical actual variations or larger of every utility instrument described above. To run and check the React Native software, all you want is an Expo consumer put in both in your gadget or an iOS simulator or an Android emulator. Please notice that, all through this tutorial, I will probably be utilizing an iOS simulator to reveal the appliance.
Create an Expo app
🔗
To get began, all you require is to generate a brand new Expo venture. This could possibly be achieved by opening a terminal window, navigating to an acceptable location the place you develop initiatives and operating the next instructions within the order they’re described.
expo init offline-todolist-app
cd offline-todolist-app
yarn add react-navigation native-base
expo-font@5.0.1 lodash.values uuid
The final command, as described within the above snippet installs 5 dependencies that the appliance goes to make use of. yarn
is at present getting used because the package deal supervisor. You too can use npm
as an alternative of yarn
. Using every dependency will probably be made clear as all through this tutorial as they’re used. If that is your first time constructing a React Native software, attempt to not get overwhelmed by them.
Exploring AsyncStorage
🔗
AsyncStorage
is a straightforward, asynchronous key-value pair utilized in React Native functions. It’s used for quite a lot of eventualities however primarily to retailer knowledge when your app isn’t utilizing any cloud providers, otherwise you need to implement some options in your app that require knowledge storage.
It operates globally in a React Native and comes with its personal limitations. As a React Native developer, you need to know what these limitations. The primary limitation of an AsyncStorage
API is that the dimensions of the database is ready to 6MB
restrict. Additionally, AsyncStorage
storage relies on SQLite. Thus, you will need to preserve SQLite limitations in thoughts too. Additionally, it’s exhausting to retailer complicated and nested knowledge constructions in type of key-value pairs. Figuring out about these limitations, solely assist you to to go for the persistent resolution when growing a cell app.
In line with the React Native’s official documentation:
On iOS, AsyncStorage is backed by native code that shops small values in a serialized dictionary and bigger values in separate recordsdata. On Android, AsyncStorage will use both RocksDB or SQLite primarily based on what is obtainable.
Using AsyncStorage API
🔗
Earlier than you dive deep in constructing the Todolist app, on this part, allow us to construct a small app that saves a price to the AsyncStorage
, fetches the worth from the storage within the client-side React Native app. It will assist you to the best way to write fundamental operations utilizing the storage API. Lastly, you’ll study the best way to clear the storage utterly.
Open App.js
file and add the next snippet. Begin by importing the mandatory parts from React Native API. Crucial one right here is AsyncStorage
. After that, outline a variable named STORAGE_KEY
. This variable will probably be used to retailer and retrieve the saved knowledge utilizing the AsyncStorage
API. Consider it as an identifier for the worth being saved or title of the important thing within the key-value pair. Since you’ll retailer just one worth in the meanwhile, there may be solely the requirement for one key.
1import React from 'react';
2import {
3 StyleSheet,
4 Textual content,
5 View,
6 TextInput,
7 AsyncStorage,
8 TouchableOpacity
9} from 'react-native';
10
11const STORAGE_KEY = '@save_name';
Subsequent, allow us to outline an preliminary state with two empty strings. They’ll be used to avoid wasting the worth of the consumer enter after which retrieve the worth to show it on the app display. After defining the preliminary state, there may be going to be a lifecycle methodology that’s going to load the info when the appliance begins for the primary time or the App element renders.
1class App extends React.Part {
2 state = {
3 textual content: '',
4 title: ''
5 };
6
7 componentDidMount() {
8 this.retrieveData();
9 }
10
11
12}
Within the above snippet, do notice that the App
element is definitely a category element and never the default purposeful element that comes with boilerplate Expo app. Now, there are going to be three strategies that can assist to retailer the info, retrieve the info, and clear the app knowledge that’s saved. That is going to be achieved by creating three asynchronous strategies. Every of the strategies goes to make the most of the suitable API methodology from AsyncStorage
API. Each methodology within the AsyncStorage
API is a promise-based, therefore, allow us to use async/await
syntax to observe good follow.
1retrieveData = async () => {
2 attempt {
3 const title = await AsyncStorage.getItem(STORAGE_KEY);
4
5 if (title !== null) {
6 this.setState({ title });
7 }
8 } catch (e) {
9 alert('Did not load title.');
10 }
11};
Within the above snippet, the title of the tactic implies what they’re going to do within the app. The retrieveData
methodology is what fetches the info from the storage if it exists. It makes use of the identical identifier that you simply outlined beforehand, outdoors the category perform element. It utilises the parameter within the state object title
. Later within the app, you’ll use this parameter to show its saved worth. Be aware that, there may be an if
situation inside this methodology. This situation says that to fetch the info solely when there’s a worth for the title
variable exists. This methodology additionally makes use of attempt/catch
as they’re half and parcel of writing capabilities with fashionable async/await
syntax. Lastly, this methodology is being invoked contained in the lifecycle methodology.
The subsequent perform goes to avoid wasting the info. Within the beneath snippet, you’ll discover that it makes use of a parameter title
which on success, is the worth that’s saved. An alert message will probably be proven when the enter knowledge is saved.
1save = async title => {
2 attempt {
3 await AsyncStorage.setItem(STORAGE_KEY, title);
4 alert('Information efficiently saved!');
5 this.setState({ title });
6 } catch (e) {
7 alert('Failed to avoid wasting title.');
8 }
9};
The final methodology that you’re going to make the most of from the AsyncStorage
API known as clear()
. This deletes all the pieces that’s beforehand saved. It’s not really helpful to make use of this methodology immediately if you wish to delete solely a selected merchandise from the storage. For that, there are strategies like removeItem
or multiRemove
out there by the API. You’ll be able to learn extra about them within the official documentation right here or later when constructing the Todolist software.
1removeEverything = async () => {
2 attempt {
3 await AsyncStorage.clear();
4 alert('Storage efficiently cleared!');
5 } catch (e) {
6 alert('Did not clear the async storage.');
7 }
8};
This snippet will throw an Alert
field on the gadget display when all the pieces is cleared from the storage.
The final two strategies are going for use to create a managed enter.
1onChangeText = textual content => this.setState({ textual content });
2
3onSubmitEditing = () => {
4 const onSave = this.save;
5 const { textual content } = this.state;
6
7 if (!textual content) return;
8
9 onSave(textual content);
10 this.setState({ textual content: '' });
11};
After that, add the code snippet for the render
methodology, adopted by the types for every UI element. Lastly, don’t forget to export App
element for it to run on the simulator or the actual gadget.
1render() {
2 const { textual content, title } = this.state
3 return (
4 <View fashion={types.container}>
5 <TextInput
6 fashion={types.enter}
7 worth={textual content}
8 placeholder='Kind your title, hit enter, and refresh'
9 onChangeText={this.onChangeText}
10 onSubmitEditing={this.onSubmitEditing}
11 />
12 <Textual content fashion={types.textual content}>Hiya {title}!</Textual content>
13 <TouchableOpacity onPress={this.removeEverything} fashion={types.button}>
14 <Textual content fashion={types.buttonText}>Clear Storage</Textual content>
15 </TouchableOpacity>
16 </View>
17 )
18 }
19}
20
21const types = StyleSheet.create({
22 container: {
23 flex: 1,
24 backgroundColor: '#fff',
25 alignItems: 'heart',
26 justifyContent: 'heart'
27 },
28 textual content: {
29 fontSize: 20,
30 padding: 10,
31 backgroundColor: '#00ADCF'
32 },
33 enter: {
34 padding: 15,
35 top: 50,
36 borderBottomWidth: 1,
37 borderBottomColor: '#333',
38 margin: 10
39 },
40 button: {
41 margin: 10,
42 padding: 10,
43 backgroundColor: '#FF851B'
44 },
45 buttonText: {
46 fontSize: 14,
47 coloration: '#fff'
48 }
49})
50
51export default App
Now to run the appliance, go to the terminal window and execute the command expo begin
. After that, you will notice the next display on the simulator.
Since there is no such thing as a knowledge saved proper now, the textual content after the phrase Hiya
is empty. Use the enter area to avoid wasting a string or a reputation or something after which press the enter key. You’re going to get the next output. No matter enter you entered, will probably be displayed subsequent to the phrase Hiya
.
Even in case you refresh the Expo consumer, the worth saved doesn’t go away. Solely when urgent the button beneath Hiya
assertion that claims Clear Storage
is the way in which to delete the saved worth.
Refresh the Expo consumer after you clear the storage to get the next output.
This entire the part the place you discovered about the best way to make the most of AsyncStorage
API to avoid wasting and fetch the info. From the subsequent part onwards, you can be constructing the Todolist software.
Organizing the appliance
🔗
Since a React Native software was already generated within the earlier step, you may proceed to make the most of that app by modifying all the pieces contained in the App.js
file. Or create a brand new one if it serves you properly.
You’ve gotten already put in the mandatory npm modules. That is the time to begin using them with a view to construct the offline todo record app. Earlier than starting with the event of the app, create the next folders and recordsdata inside them. It will give a construction to handle the app later or if you wish to prolong by including new options to it.
From the construction, discover that there are three new folders being created. This construction is the separation of considerations between the completely different side of a cell app. Equivalent to recordsdata or configuration associated to navigation must be separated from the screens. The above construction can be a typical sample that many React Native builders have began to observe of their work.
Including Navigation
🔗
Contained in the navigation
folder, there may be an index.js
file that’s going to carry all of the configuration there may be to be outlined. The rationale react-navigation
module is used is to create a stack navigator that enables the consumer to go to the 2 screens the next software has. The navigation mode goes to be modal
. Sure, you may make the most of pre-defined
navigation modes or animation patterns.
Allow us to begin by importing the mandatory parts contained in the index.js
file.
1import React from 'react';
2import { createStackNavigator, createAppContainer } from 'react-navigation';
3import HomeScreen from '../screens/HomeScreen';
4import AddTaskScreen from '../screens/AddTaskScreen';
From the above snippet, discover that the createStackNavigator
is a perform that returns a React element. It takes a route configuration object. The createAppContainer
is chargeable for linking the present React Native app whereas sustaining the navigation state from the top-level element. The highest-level element in your app is App
.
With the assistance of createAppContainer
, you’ll create a supplier and wrap the App
element inside it. It will profit the whole software as each display or element outlined goes to have a navigation state. You’ll study a few of the many advantages offered by the navigation state later.
Lastly, within the above snippet, there are going to be a display element. These display parts are going to carry the enterprise logic essential to run the todo record app. You’ll be able to consider them as containers.
Proper now, the route configuration object goes to be as the next snippet.
1const StackNav = createStackNavigator(
2 {
3 Residence: {
4 display: HomeScreen
5 },
6 AddTask: {
7 display: AddTaskScreen
8 }
9 },
10 {
11 mode: 'modal'
12 }
13);
The mode
is necessary to specify right here. It defines the fashion for rendering the subsequent display element. Within the above case, it’s AddTask
display. In an iOS or Android app, the default transition is all the time a card
. You’re altering this default transition by specifying the mode
property and setting its worth to modal
.
The modal
sample Make the screens slide in from the underside, which is a typical iOS sample. Solely works on iOS however has no impact on Android.
Lastly, you need to export the app container that makes use of the StackNav
. Right here is the code for that.
1const RootNavigator = createAppContainer(StackNav);
2
3export default RootNavigator;
Now, open App.js
file and add the next content material.
1import React from 'react';
2import RootNavigator from './navigation';
3
4export default perform App() {
5 return <RootNavigator />;
6}
Earlier than operating the app, be sure there’s a mock element to render contained in the recordsdata HomeScreen.js
and AddTaskScreen.js
. In any other case, it should throw an error. You’ll be able to add the dummy element for now.
1
2import React, { Part } from 'react';
3import { Textual content, View } from 'react-native';
4
5export class HomeScreen extends Part {
6 render() {
7 return (
8 <View>
9 <Textual content> Offline Todolist App</Textual content>
10 </View>
11 );
12 }
13}
14
15export default HomeScreen;
16
17
18import React, { Part } from 'react';
19import { Textual content, View } from 'react-native';
20
21export class AddTaskScreen extends Part {
22 render() {
23 return (
24 <View>
25 <Textual content>Add Job Display</Textual content>
26 </View>
27 );
28 }
29}
30
31export default AddTaskScreen;
Now run the app utilizing expo begin
command, and you’ll get the next consequence.
This completes the navigation part.
Create a Floating button
🔗
Contained in the parts/FloatingButton.js
file, you’ll create a floating motion button or in cell growth, generally generally known as FABs. These sort of buttons are sometimes distinguished by a circled icon floating above the UI in a hard and fast place. In case you are an Android consumer or have seen a cell app following any materials design specification, you might need seen them.
Within the present app, this FloatingButton
goes to be chargeable for navigating from the HomeScreen
to the AddTaskScreen
. Since it’ll be a presentation element, it is best to outline it as a purposeful element that accepts just one prop. This prop actionOnPress
goes to be a technique outlined contained in the HomeScreen.js
file that can comprise the logic of navigating between the 2 screens later.
One necessary factor to note within the snippet beneath is that the element library native-base
is getting used to create the FAB button. It saves period of time and features of code to create and elegance a element like beneath.
1import React from 'react';
2import { StyleSheet } from 'react-native';
3import { Icon, Fab } from 'native-base';
4
5const FloatingButton = ({ actionOnPress }) => (
6 <Fab
7 route="up"
8 fashion={types.button}
9 place="bottomRight"
10 onPress={actionOnPress}
11 >
12 <Icon title="ios-add" />
13 </Fab>
14);
15
16const types = StyleSheet.create({
17 button: {
18 backgroundColor: '#5859f2'
19 }
20});
21
22export default FloatingButton;
Navigating Between Two Screens
🔗
Upon getting outlined it, go to the file HomeScreen.js
and the next snippet of code.
1import React, { Part } from 'react';
2import { View, Textual content, StyleSheet } from 'react-native';
3import { AppLoading } from 'expo';
4import * as Font from 'expo-font';
5import FloatingButton from '../parts/FloatingButton';
6
7export class HomeScreen extends Part {
8 state = {
9 isDataReady: false
10 };
11 componentDidMount = () => {
12 this.loadFonts();
13 };
14
15 loadFonts = async () => {
16 attempt {
17 await Font.loadAsync({
18 Roboto: require('../node_modules/native-base/Fonts/Roboto.ttf'),
19 Roboto_medium: require('../node_modules/native-base/Fonts/Roboto_medium.ttf'),
20 Ionicons: require('../node_modules/native-base/Fonts/Ionicons.ttf')
21 });
22 this.setState({ isDataReady: true });
23 } catch (err) {
24 alert('Software Error. Can't load fonts.');
25 }
26 };
27
28 onPressFab = () => {
29 this.props.navigation.navigate('AddTask');
30 };
31
32 render() {
33 const { isDataReady } = this.state;
34
35 if (!isDataReady) {
36 return <AppLoading />;
37 }
38 return (
39 <View fashion={types.container}>
40 <Textual content>Residence Display</Textual content>
41 <FloatingButton actionOnPress={this.onPressFab} />
42 </View>
43 );
44 }
45}
46
47const types = StyleSheet.create({
48 container: {
49 flex: 1
50 }
51});
52
53export default HomeScreen;
Within the above snippet, the primary and necessary factor to note is the loadFonts
methodology. This asynchronous methodology is a requirement to make Native Base UI library to work in any React Native, and Expo generated software. NativeBase use some customized fonts which are loaded utilizing Font.loadAsync
perform. This perform is offered by the expo module expo-font
which lets you use any fonts or icons in React Native parts.
The AppLoading
methodology is a React element that tells Expo to maintain the app loading display seen till Font.loadAsync()
the tactic has run efficiently. Basically, this a helpful methodology to make the most of when your app is utilizing customized fonts, logos, icons, and so forth. Within the present software, you’ll make the most of this React element once more when fetching knowledge from AsyncStorage
API (that you will notice in motion later on this tutorial). The AppLoading
will solely cease operating when the boolean worth for the state variable isDataReady
is ready to true. This boolean worth is barely set to true when Font.loadAsync()
has completed operating.
As soon as the appliance has loaded all vital fonts and icons, you’ll get the next consequence.
From the above snippet, check out the tactic onPressFab
which is being handed to the FloatingButton
element because the prop actionOnPress
. This perform makes use of a navigation methodology offered known as navigation.navigate()
with the worth of the display being handed because the argument: AddTask
. Do notice that, the worth of the argument being handed must be the precise title of the display outlined earlier when configuring StackNavigator
. Click on on the button, and you can be directed to the subsequent display.
Did you discover the again
button on the AddTaskScreen
? That is once more the place react-navigation
is useful. Whereas engaged on a real-time React Native software, you usually need to use the react-navigation
library if it fits your necessities. It gives easy options out of the field.
Customise the Header Part
🔗
With Native Base parts library, it’s simple to customise a header element in few strains of code. Contained in the file Header.js
add the next snippet. Once more, it is a purposeful element since it’ll improve the UI and isn’t operating enterprise logic.
1import React from 'react';
2import { Header as NBHeader, Physique, Title } from 'native-base';
3
4const Header = () => {
5 return (
6 <NBHeader fashion={{ backgroundColor: '#5859f2' }}>
7 <Physique>
8 <Title fashion={{ coloration: '#ffffff' }}>Header</Title>
9 </Physique>
10 </NBHeader>
11 );
12};
13
14export default Header;
The Header
element from the native-base
library takes a Physique
as an enter. The physique can additional comprise the rendering logic to switch the present default Header
element from the native base library itself. You should use inline types and even StyleSheet
object from react-native
to customise the Header
element as above, or another native base UI element usually. Check out the backgroundColor
and the coloration
to the Title
. Title
is the place the textual content to be displayed on this element goes.
Import this element contained in the HomeScreen.js
file. Additionally, import the StatusBar
element from the react-native
. Because the background of the Header
element goes to be a customise blue coloration, it’s higher to vary the default darkish StatusBar
fashion into one thing pleasing and lightweight.
1import { View, Textual content, StyleSheet, StatusBar } from 'react-native';
2import Header from '../parts/Header';
Inside the category element, the very first thing you need to do is conceal the header that’s being offered by the stack navigator from react-navigation
library. The thing navigationOptions
is the best way to customise the default navigators that react-navigation
renders.
1 static navigationOptions = {
2 header: null
3 }
Subsequent, contained in the render()
methodology add the next earlier than the omnipresent Textual content
element.
1<Header />
2<StatusBar barStyle='light-content' />
3<Textual content>Residence Display</Textual content>
The remainder of the code contained in the HomeScreen.js
file stays unchanged. The StatusBar
is modified by defining the a price utilizing its pre-defined prop barStyle
. When utilizing a Header element from Native Base UI library, the StatusBar
from React Native comes after you outline the JSX code for the header. Discover this within the above snippet. That is the way it works with Native Base library. The next display is what you get as the results of the above snippets.
Rendering an inventory of things utilizing FlatList
🔗
On this part, you’ll arrange a Checklist element that accepts mock or dummy knowledge from an array outlined as a property to the preliminary state. Open HomeScreen.js
file and modify the state for now.
1state = {
2 isDataReady: false,
3 mockItems: ['First Item', 'Second Item', 'Third Item']
4};
Why dummy knowledge? Later when you’ll hook AsyncStorage
API to avoid wasting and fetch the info from the database, in different phrases, enjoying round with real-time knowledge operations, there are going to be separate strategies which are going to deal with every of the info operations. For now, allow us to hook up the enterprise logic to show an inventory of things in addition to the power so as to add a brand new merchandise utilizing the modal display you will have arrange within the earlier steps.
The FlatList
element is the perfect solution to show an inventory of things in a React Native software.
It’s a cross-platform element, and by default a vertical solution to show an inventory of information gadgets. It requires two props: knowledge
and renderItem
. The knowledge
is the supply of data for the record within the type of an array. The renderItem
takes one merchandise from the supply, iterates over them, and returns a formatted element to render these gadgets.
Kinds that may be utilized to a FlatList element is finished by the prop contentContainerStyle
that accepts the worth of Stylesheet object. The rationale to make use of FlatList
is that it’s efficiency efficient. After all, you need to use ScrollView
however it renders gadgets from reminiscence, which isn’t a really performant efficient solution to show a prolonged record of things. ScrollView
is a wrapper on the View element that gives the consumer interface for scrollable lists inside a React Native app.
Within the file HomeScreen.js
exchange the Textual content
element with following FlatList
and don’t forget to import it and customized presentational element Merchandise
that’s going to show every merchandise within the record.
1
2import { View, FlatList, StyleSheet, StatusBar } from 'react-native';
3import Merchandise from '../parts/Merchandise';
4
5
6<FlatList
7 knowledge={this.state.mockItems}
8 contentContainerStyle={types.content material}
9 renderItem={row => {
10 return <Merchandise textual content={row.merchandise} />;
11 }}
12 keyExtractor={merchandise => merchandise.id}
13/>;
Now open the file parts/Merchandise.js
and add the next snippet.
1import React from 'react';
2import {
3 View,
4 Textual content,
5 StyleSheet,
6 TouchableOpacity,
7 Dimensions
8} from 'react-native';
9
10const { width } = Dimensions.get('window');
11
12const Merchandise = ({ textual content }) => {
13 return (
14 <View fashion={types.container}>
15 <View fashion={types.rowContainer}>
16 <Textual content fashion={types.textual content}>{textual content}</Textual content>
17 </View>
18 </View>
19 );
20};
21
22const types = StyleSheet.create({
23 container: {
24 borderBottomColor: '#5859f2',
25 borderBottomWidth: StyleSheet.hairlineWidth,
26 flexDirection: 'row',
27 alignItems: 'heart',
28 justifyContent: 'space-between'
29 },
30 rowContainer: {
31 flexDirection: 'row',
32 width: width / 2,
33 alignItems: 'heart'
34 },
35 textual content: {
36 coloration: '#4F50DC',
37 fontSize: 18,
38 marginVertical: 20,
39 paddingLeft: 10
40 }
41});
42
43export default Merchandise;
One other new React Native element to note within the above snippet is Dimensions
. It helps to set the preliminary width
and top
of a element earlier than the appliance runs. We’re utilizing its get()
methodology to accumulate the present gadget’s width and top.
Within the simulator, you’ll get the next consequence.
Studying Information utilizing AsyncStorage API
🔗
On this part, you’ll add all strategies that can comprise enterprise logic to avoid wasting and fetch the info from the AsyncStorage
. This logic will probably be composed of three operations:
- add a todolist merchandise
- fetch all gadgets to show
- delete an merchandise from the record
- additionally, examine the state of every record merchandise whether or not it’s marked as accomplished or not
These operations are going to speak with the realtime knowledge on the gadget. You will use objects as an alternative of an array to retailer this stuff. AsyncStorage
operates on key-value pairs and never arrays. Every object goes to be recognized by a singular ID. With the intention to generate distinctive IDs, you’ll use a module known as uuid
which was put in earlier.
The construction of every todo merchandise goes to be like this:
145745c60-7b1a-11e8-9c9c-2d42b21b1a3e: {
2 id: 45745c60-7b1a-11e8-9c9c-2d42b21b1a3e,
3 textValue: 'New merchandise',
4 isCompleted: false,
5 createdAt: Date.now()
6}
But when you’ll use Objects as an alternative of an array, how are you going to iterate over every merchandise within the object? FlatList
element solely takes an array to iterate. Nicely, do you bear in mind putting in a utility package deal known as lodash.values
? That package deal goes to be actually useful in changing the thing into an array.
First, allow us to begin by importing all parts and customized parts required with a view to construct the appliance inside HomeScreen.js
file.
1import React, { Part } from 'react';
2import {
3 FlatList,
4 View,
5 StatusBar,
6 StyleSheet,
7 AsyncStorage
8} from 'react-native';
9import uuidv1 from 'uuid/v1';
10import _values from 'lodash.values';
11import { Button, Textual content as NBText } from 'native-base';
12import { AppLoading } from 'expo';
13import * as Font from 'expo-font';
14import Header from '../parts/Header';
15import Merchandise from '../parts/Merchandise';
16import FloatingButton from '../parts/FloatingButton';
After writing these import statements, allow us to modify the preliminary state.
1state = {
2 todos: {},
3 isDataReady: false
4};
From the above snippet, do take a notice that the dummy array of information is changed by the thing todos
. Subsequent, you’ll write an asynchronous methodology to load the todos gadgets from the thing that’s saved utilizing AsyncStorage
API. Additionally, allow us to merge the earlier asynchronous methodology to load all of the fonts with this methodology, corresponding to the worth of the preliminary state isDataReady
is ready to the boolean true
solely as soon as. Additionally, you will have to switch the contents of the lifecycle methodology.
1componentDidMount = () => {
2 this.loadTodos();
3};
4
5loadTodos = async () => {
6 attempt {
7 await Font.loadAsync({
8 Roboto: require('../node_modules/native-base/Fonts/Roboto.ttf'),
9 Roboto_medium: require('../node_modules/native-base/Fonts/Roboto_medium.ttf')
10 });
11
12 const getTodos = await AsyncStorage.getItem('todos');
13 const parsedTodos = JSON.parse(getTodos);
14 this.setState({ isDataReady: true, todos: parsedTodos || {} });
15 } catch (err) {
16 alert('Software Error. Can't load knowledge.');
17 }
18};
AsyncStorage.getItem()
reads something saved on the gadget database. It’s important to parse the info incoming from the storage into JSON. In case you are not parsing the info, the appliance goes to crash. When setting the state within the above snippet, the todos
object is getting the default worth of an empty object is there is no such thing as a knowledge from the storage. That is additionally a necessary step to carry out and remember for different use instances with related eventualities.
Including a Todolist Merchandise
🔗
Now, allow us to add the second methodology addTodo
that’s really going so as to add the brand new merchandise within the storage. The strategy defines earlier than addTodo
is definitely storing the gadgets within the storage. Once more, you might be utilizing JSON.stringify()
since AsyncStorage requires the info to be a string inside the only object. So when saving the merchandise in case you are not utilizing JSON.stringify()
your app goes to crash.
The AsyncStorage.setItem()
is the perform from the API that’s just like any key-value paired database. It takes the primary argument, todos
within the snippet beneath. This argument worth goes to be the title of the shop.
The parameter newTask
handed to the addTodo
perform goes to be the thing. Utilizing if
assertion, there’s a examine whether or not the todo merchandise being entered isn’t empty. this.setState
makes use of a callback methodology that has entry to prevState
object. It offers any todo merchandise that has been beforehand added to the record.
Contained in the callback, you might be first creating a brand new ID utilizing uuidv1
methodology. Then create an object known as newTodoObject
which makes use of the ID as a variable for the title. This object represents every merchandise within the todo record.
Additional, create a brand new object known as newState
which makes use of the prevState
object, and eventually provides newTodoObject
object in todoliist of things. It would sound overwhelming since lots is occurring however attempt implementing the code, you’ll perceive it higher.
1saveTodos = newToDos => {
2 const saveTodos = AsyncStorage.setItem('todos', JSON.stringify(newToDos));
3};
4
5addTodo = newTask => {
6 const newTodoItem = newTask;
7
8 if (newTodoItem !== '') {
9 this.setState(prevState => {
10 const ID = uuidv1();
11 const newToDoObject = {
12 [ID]: {
13 id: ID,
14 isCompleted: false,
15 textValue: newTodoItem,
16 createdAt: Date.now()
17 }
18 };
19 const newState = {
20 ...prevState,
21 todos: {
22 ...prevState.todos,
23 ...newToDoObject
24 }
25 };
26 this.saveTodos(newState.todos);
27 return { ...newState };
28 });
29 }
30};
Deleting a Todolist Merchandise
🔗
Just like the addTodo
methodology, you’ll add one other methodology known as deleteTodo
. It will care for eradicating a person merchandise from the record on the idea of id
of that merchandise object. Since you might be utilizing the id
of the thing each to determine the thing inside the larger object todos
and assign every particular person object the identical id
, the next code saves a variety of time. Eventually, utilizing the saveTodos
methodology, the storage is being up to date with a remaining variety of gadgets.
1deleteTodo = id => {
2 this.setState(prevState => {
3 const todos = prevState.todos;
4 delete todos[id];
5 const newState = {
6 ...prevState,
7 ...todos
8 };
9 this.saveTodos(newState.todos);
10 return { ...newState };
11 });
12};
Mark a Todo Merchandise Test or Uncheck on completion
🔗
The final two strategies which are going to care for whether or not every particular person merchandise is checked or not are going to be represented by inCompleteTodo
and completeTodo
strategies. Each of those strategies are going observe which gadgets within the to-do record have been marked accomplished by the consumer or have been unmarked.
They’ll act as a toggle and solely replace the worth of isCompleted
as an alternative quite updating the entire todo record merchandise object. That is once more, attainable due to a singular id
for every object. Once more within the final, earlier than every of the strategies returns the brand new state, utilizing the saveTodos
methodology, the storage will get an replace.
1inCompleteTodo = id => {
2 this.setState(prevState => {
3 const newState = {
4 ...prevState,
5 todos: {
6 ...prevState.todos,
7 [id]: {
8 ...prevState.todos[id],
9 isCompleted: false
10 }
11 }
12 };
13 this.saveTodos(newState.todos);
14 return { ...newState };
15 });
16};
17
18completeTodo = id => {
19 this.setState(prevState => {
20 const newState = {
21 ...prevState,
22 todos: {
23 ...prevState.todos,
24 [id]: {
25 ...prevState.todos[id],
26 isCompleted: true
27 }
28 }
29 };
30 this.saveTodos(newState.todos);
31 return { ...newState };
32 });
33};
Passing Information between completely different screens utilizing the navigation
🔗
On this part, you’ll edit every render methodology that’s chargeable for displaying the interface for the operations you outlined within the earlier sections, to occur in realtime. Allow us to begin by enhancing onPressFab
methodology contained in the HomeScreen.js
.
This methodology proper navigates to the AddTaskScreen
. By passing an object with so as to add a brand new merchandise to the record (therefore, cross the tactic addTodo) you’ll make the most of one other benefit {that a} glossy library react-navigation
gives. That’s, to cross knowledge between completely different screens.
First, edit the onPressFab
methodology just like the beneath snippet.
1onPressFab = () => {
2 this.props.navigation.navigate('AddTask', {
3 saveItem: this.addTodo
4 });
5};
Subsequent, open AddTaskScreen.js
and add the next snippet.
1import React, { Part } from 'react';
2import { View } from 'react-native';
3import { Type, Merchandise, Enter, Button, Textual content as NBText } from 'native-base';
4
5export class AddTaskScreen extends Part {
6 state = {
7 textual content: ''
8 };
9
10 onChangeText = occasion => {
11 this.setState({ job: occasion.nativeEvent.textual content });
12 };
13
14 onAddTask = () => {
15 this.props.navigation.state.params.saveItem(this.state.job);
16 this.props.navigation.goBack();
17 };
18
19 render() {
20 return (
21 <View>
22 <View fashion={{ marginRight: 10 }}>
23 <Type>
24 <Merchandise>
25 <Enter
26 worth={this.state.job}
27 placeholder="Enter a brand new job..."
28 autoFocus
29 clearButtonMode="all the time"
30 autoCorrect={false}
31 onChange={this.onChangeText}
32 onSubmitEditing={this.onAddTask}
33 returnKeyType={'achieved'}
34 />
35 </Merchandise>
36 </Type>
37 </View>
38 <View fashion={{ marginTop: 20 }}>
39 <Button
40 fashion={{
41 backgroundColor: '#5067FF',
42 margin: 25,
43 justifyContent: 'heart'
44 }}
45 onPress={this.onAddTask}
46 >
47 <NBText fashion={{ fontWeight: 'daring' }}>Add Job</NBText>
48 </Button>
49 </View>
50 </View>
51 );
52 }
53}
54
55export default AddTaskScreen;
The snippet above makes use of the native base library to create a managed enter kind to let the consumer add a brand new merchandise to the todo record. Subsequent, it has a button so as to add the merchandise. Because the Enter
element from Native Base relies on the React Native’s TextInput
, you need to use all of the props which are out there to TextInput
.
Additionally, take a notice that, to create an enter area when utilizing Native base because the UI library, the Enter
element must be wrapped by an Merchandise
which is additional wrapped inside Type
factor.
Here’s a transient overview of the props used within the above snippet.
- worth: the worth of the textual content enter. By default, will probably be an empty string since we’re utilizing the native state to set it. Because the state updates, the worth of the textual content enter updates.
- placeholder: identical to in HTML, a placeholder is to outline a default message within the enter area indicating as if what is anticipated.
- onChange: is a callback that known as when the textual content enter’s textual content adjustments. Modified textual content is handed as an argument to the callback handler
onChangeText
. This handler accepts the textual content worth fromoccasion.nativeEvent
. - clearButtonMode: a transparent button ought to seem on the suitable aspect of the textual content view. The default worth is
by no means
that you’re modifying toall the time
within the above element. - returnKeyType: determines how the return key on the gadget’s keyboard ought to look. Yow will discover extra values or platform-specific values right here. A few of the values are particular to every platform.
- autoCorrect: this prop allow us to determine whether or not to indicate the autocorrect bar together with keyboard or not. Within the present case, you will have set it to false.
- onSubmitEditing: accommodates the enterprise the logic within the type of a callback as to what to do when the return key or enter’s submit button is pressed. We will probably be defining this callback in Essential.js.
Lastly, check out the tactic onAddTask
which makes use of navigation state to avoid wasting the textual content worth of the todo merchandise. After use presses the button or the handler onSubmitEditing
triggers, it’ll additional run the tactic addTodo
from HomeScreen
and navigate again to the HomeScreen
itself, utilizing the navigation props methodology goBack()
.
On Clicking the Fab button, you get the next display.
Show every todo record merchandise
🔗
To show every todo record merchandise, you should have first to cross the props as proven beneath utilizing the renderItem
within the FlatList
.
1<Merchandise
2 isCompleted={row.merchandise.isCompleted}
3 textValue={row.merchandise.textValue}
4 id={row.merchandise.id}
5 deleteTodo={this.deleteTodo}
6 completeTodo={this.completeTodo}
7 inCompleteTodo={this.inCompleteTodo}
8/>
Subsequent, go to Merchandise.js
file and add the next snippet.
1import React from 'react';
2import {
3 View,
4 Textual content,
5 StyleSheet,
6 TouchableOpacity,
7 Dimensions
8} from 'react-native';
9import { Icon } from 'native-base';
10
11const { width } = Dimensions.get('window');
12
13const Merchandise = ({
14 inCompleteTodo,
15 completeTodo,
16 textValue,
17 id,
18 deleteTodo,
19 isCompleted
20}) => {
21 toggleItem = () => {
22 if (isCompleted) {
23 inCompleteTodo(id);
24 } else {
25 completeTodo(id);
26 }
27 };
28
29 return (
30 <View fashion={types.container}>
31 <View fashion={types.rowContainer}>
32 <TouchableOpacity onPress={this.toggleItem}>
33 <Icon
34 title={isCompleted ? 'checkmark-circle' : 'radio-button-off'}
35 fashion={{ paddingLeft: 10, coloration: '#7A7AF6' }}
36 />
37 </TouchableOpacity>
38
39 <Textual content
40 fashion={[
41 styles.text,
42 {
43 opacity: isCompleted ? 0.5 : 1.0,
44 textDecorationLine: isCompleted ? 'line-through' : 'none',
45 color: isCompleted ? '#7A7AF6' : '#4F50DC'
46 }
47 ]}
48 >
49 {textValue}
50 </Textual content>
51 </View>
52 <TouchableOpacity onPressOut={() => deleteTodo(id)}>
53 <Icon title="md-trash" fashion={{ coloration: '#ABADF9', paddingRight: 10 }} />
54 </TouchableOpacity>
55 </View>
56 );
57};
58
59const types = StyleSheet.create({
60 container: {
61 borderBottomColor: '#5859f2',
62 borderBottomWidth: StyleSheet.hairlineWidth,
63 flexDirection: 'row',
64 alignItems: 'heart',
65 justifyContent: 'space-between'
66 },
67 textual content: {
68 coloration: '#4F50DC',
69 fontSize: 18,
70 marginVertical: 20,
71 paddingLeft: 10
72 },
73
74 rowContainer: {
75 flexDirection: 'row',
76 width: width / 2,
77 alignItems: 'heart'
78 }
79});
80
81export default Merchandise;
Within the above snippet, the important thing factors to notice are, utilizing Native Base, you need to use the Icon
element (since you might be already loading the Ionicons library within the dad or mum element asynchronously). Subsequent, the props Merchandise
parts obtain are to toggle an merchandise’s state of whether or not it’s full or not, show the textual content worth of the merchandise and lastly, a button to delete the merchandise itself.
Save the element file, hop again on the simulator file, and take a look at including one or many gadgets on this record.
See all the pieces works. Even on refreshing the app, and the gadgets don’t disappear.
Bonus Part: Including a Section
🔗
On this part, you’ll separate the UI for managing the finished record of things and gadgets which are pending to be achieved. To supply this function, you’ll use Native Base library solely.
Retaining the info supply identical from the storage API, let modify the state by including yet one more property. Open HomeScreen.js
file and add the next.
1
2state = {
3 todos: {},
4 isDataReady: false,
5 filter: 'Todo'
6};
The worth of the filter
goes to be Todo
by default. This implies it’ll present the pending todo record gadgets as the house display to the consumer.
Subsequent, you’ll add one other handler perform known as filteredItems
. This methodology will consider the worth of the state and filter the values from the todos
to match the state. Once more, to make use of JavaScript filter methodology, you’ll convert todos
object utilizing lodash methodology _values
.
1filteredItems = () => {
2 if (this.state.filter === 'Todo') {
3 return _values(this.state.todos).filter(i => {
4 return !i.isCompleted;
5 });
6 }
7 if (this.state.filter === 'Full') {
8 return _values(this.state.todos).filter(i => {
9 return i.isCompleted;
10 });
11 }
12 return this.state.todos;
13};
Subsequent, allow us to modify the render methodology to attain the specified consequence. Contained in the render methodology, you’ll add a brand new UI factor from Native base known as Section
. That is going to show two buttons, every of which may be activated when pressed. The activation of every this button will depend on the worth of the state property filter
.
1
2import { Button, Textual content as NBText, Section } from 'native-base'
3
4
5
6const { isDataReady, filter } = this.state
7
8
9
10 <View fashion={types.contentHeader}>
11 <Section fashion={{ backgroundColor: '#ffffff' }}>
12 <Button energetic={filter === 'Todo'} onPress={() => this.setState({ filter: 'Todo' })}>
13 <NBText>Todo</NBText>
14 </Button>
15 <Button
16 final
17 energetic={filter === 'Full'}
18 onPress={() => this.setState({ filter: 'Full' })}
19 >
20 <NBText>Full</NBText>
21 </Button>
22 </Section>
23 </View>
24
25
26
27contentHeader: {
28 alignItems: 'heart',
29 justifyContent: 'heart'
30}
Lastly, change the worth of the knowledge
prop on FlatList
and set it to the merchandise returned from the tactic filteredItems()
.
1<FlatList
2 knowledge={_values(this.filteredItems())}
3
4/>
You’re going to get the next consequence.
Conclusion
🔗
Congratulations! You’ve gotten simply discovered the best way to construct an offline cell software utilizing newest tech stack and libraries like React Native, Expo, and Native Base element UI. You’ve gotten discovered many key factors on this tutorial, and I hope you loved following it, and studying it. Use the data you will have gained on this tutorial in a realtime software and present it to your friends. The chances to reinforce this software or the use the data is countless.
I am a software program developer and a technical author. On this weblog, I write about Technical writing, Node.js, React Native and Expo.
Presently, working at Expo. Beforehand, I’ve labored as a Developer Advocate, and Senior Content material Developer with firms like Draftbit, Vercel and Crowdbotics.