Codementor Events

Getting Started with React Native

Published Jan 22, 2018
Getting Started with React Native

Why React Native

React Native is is a framework that enables you to build cross-platform mobile applications using React and JavaScript. It enables you to use the same components on iOS and Android platforms. The UI components can also be customized for each platform.

What we will be building

This guide would walk you through building a to-do application in React Native with features like:

  • Adding a new to-do item.
  • Deleting a to-do item.
  • Marking a to-do item as done and undone.

Before you begin

Follow the instructions here to set up your React Native development environment for your development OS (macOS, Windows, or Linux) and target OS (iOS or Android).

Tools used.

  • React Native: This will be used to build our mobile application (iOS or Android) in JavaScript.
  • React Native Vector Icons: This contains icons that will be used in our React Native mobile application.

Project setup.

Navigate to a specific directory on your machine and run the following commands to generate a new React Native project.

 react-native init todo

Navigate to the project directory and start your React Native application by running the following command. Ensure you have your virtual device or emulator running.

cd todo
react-native run-android

If all things worked properly, you should have a screen like this displayed on your Android emulator or device.

initialscreen3.png

Create the src directory containing the components and styles subfolder.

The components folder will contain all of our React components while the styles folder will contain all of our stylings for the components.

mkdir -p src/{components,styles}

Adding new to-do items

Create a todoStyles.js file in the src/styles directory. This will contain all of the styles for our Todo component that we will create later. Add the code below to the file.

src/styles/todoStyles.js

import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    padding: 10,
    backgroundColor: 'white'
  },
  inputContainer: {
    height: 50
  },
  separator: {
    borderBottomColor: '#d1d0d4',
    borderBottomWidth: 1
  }
});

export default styles;

Create a todo.js file in the src/components directory and add the code below to the file.

src/components/todo.js

import React, { Component } from 'react';
import { TextInput, View } from 'react-native';
import styles from '../styles/todoStyles';

class Todo extends Component {
    constructor(props) {
        super(props);
        this.state = {
          text: '',
          todos: []
        };
      }
      onSubmit = () => {
        if (this.state.text) {
          this.setState(prevState => ({
            text: '',
            todos: [...prevState.todos,
              { title: prevState.text, done: false }]
          }));
          this.textInput.setNativeProps({ text: '' });
        }
      }
    render () {
        return (
        <View style={styles.container} >
            <TextInput
              selectionColor="black"
              underlineColorAndroid="black"
              placeholder="What needs to be done"
              onChangeText={text => this.setState({ text })}
              onSubmitEditing={this.onSubmit}
              ref={(component) => { this.textInput = component; }}
              autoFocus
              />
        </View>
        )
    }
}
export default Todo;

The todo.js file will contain most of our application code. The View React Native component acts as the container for other child components.

The TextInput is a component that enables a user to enter text. The onChangeText prop on the TextInput takes a function that is called each time the text changes. this.setState({ text }) is called in the anonymous function passed to the onChangeText prop to change the value of the text property in the state of the todo component.

The onSubmitEditing prop on the TextInput takes a function that is called each time the text is submitted. The onSubmit method in the todo class adds a new to-do item to the todos array in the state and changes the text property in the state to an empty string. An update function is passed to this.setState here because the update/new value of state depends on the current value. It enables us to always access the most updated version of the state.

A ref was added to the text input to enable us to use setNativeProps props to clear the input every time it is submitted. A ref enables us to directly manipulate elements.

Replace the contents of the App.js file in the root directory with the code below. This imports our Todo components and renders it as a child of the App component.

App.js

import React from 'react';
import {
  StyleSheet,
  Text,
  View
} from 'react-native';
import Todo from './src/components/todo';

const App = () =>
  (
    <View style={styles.container}>
      <Text style={styles.welcome}>
          React Native Todo App
      </Text>
      <Todo/>
    </View>
  );
  
const styles = StyleSheet.create({
  container: {
    flex: 1
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});
export default App;

Displaying our to-do items

Create a todoItemStyles.js file in the src/styles directory. This file will contain all of the styles for our TodoItem component which we will create later. Add the code below to the todoItemStyles.js file.

src/styles/todoItemStyles.js

import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
  container: { flex: 1, flexDirection: 'row' },
  text: {
    flex: 1,
    marginHorizontal: 10,
    textAlignVertical: 'center',
    fontSize: 18
  }
});

export default styles;

Create a todoItem.js file in the src/components directory. This file will contain the component that would display our to-do items. Add the code below to the file.

src/components/todoItem.js

import React from 'react';
import { Text, View, TouchableHighlight } from 'react-native';
import styles from '../styles/todoItemStyles';

const TodoItem = ({item}) =>
  (
    <View style={styles.container} >
      <Text style={styles.text}
      >{item.title}
      </Text>
    </View>
  );
export default TodoItem;

Import our TodoItem component in src/components/todo.js. Import the FlatList React Native element too.

...
import { TextInput, View, FlatList } from 'react-native';
import TodoItem from '../components/todoItem'
...

Add the FlatList React Native component to the return value of the render method in the Todo class in src/components/todo.js. The Flatlist react-native element would be used to display our list of to-dos.

...
         <FlatList
            ItemSeparatorComponent={this.separator}
            data={this.state.todos}
            renderItem={this.renderItem}
            keyExtractor={this.keyExtractor}
          />
 ...

Add the methods below to the Todo class in src/components/todo.js.

...
 keyExtractor = (item, index) => index;
      
 separator = () => <View style={styles.separator} />;
      
 renderItem = ({ item, index }) => (
            <TodoItem
              item={item}
              index={index}
              markAsDone={this.markAsDone}
              onPressRemove={this.onPressRemove}
            />
    );
 ...

The renderItem method returns our TodoItem component that is rendered for each item in the todos array in our Todo component's state. The separator method returns a component that is used to separate each item in the FlatList. The key extractor tells the FlatList view to use the index of the item as unique identifiers of each item in the view.

Updated src/components/Todo.js

import React, { Component } from 'react';
import { TextInput, View, FlatList } from 'react-native';
import TodoItem from '../components/todoItem';
import styles from '../styles/todoStyles';

class Todo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      text: '',
      todos: [{ title: 'test', done: false }]
    };
  }
    onSubmit = () => {
      if (this.state.text) {
        this.setState(prevState => ({
          text: '',
          todos: [...prevState.todos,
            { title: prevState.text, done: false }]
        }));
        this.textInput.setNativeProps({ text: '' });
      }
    }
    keyExtractor = (item, index) => index;

    separator = () => <View style={styles.separator} />;

    renderItem = ({ item, index }) => (
      <TodoItem
        item={item}
        index={index}
      />
    );
    render() {
      return (
        <View style={styles.container} >
          <TextInput
            selectionColor="black"
            underlineColorAndroid="black"
            placeholder="What needs to be done"
            onChangeText={text => this.setState({ text })}
            onSubmitEditing={this.onSubmit}
            ref={(component) => { this.textInput = component; }}
            autoFocus
          />
          <FlatList
            ItemSeparatorComponent={this.separator}
            data={this.state.todos}
            renderItem={this.renderItem}
            keyExtractor={this.keyExtractor}
          />
        </View>
      );
    }
}
export default Todo;

Our to-do items should now be visible after they are submitted in the TextInput.
Our app on the Android emulator should now look like this.

Screen Shot 2018-01-11 at 1.22.00 PM.png

Deleting todo items

Run the following command to install react-native-vector-icons and link it to our application.

npm install --save react-native-vector-icons
npm install
react-native link

We will need to restart our application after this.

react-native run-android

Add the method below to the Todo class insrc/components/todo.js. This method will handle the removal of to-do items from the todos array in our components state. It filters out the array item with the index passed it as an argument from the todos array in the state.

...
    onPressRemove = (index) => {
      this.setState(prevState => ({
        todos: prevState.todos.filter((_, i) => i !== index)
      }));
    }
...

Update renderItem method in the todo class to include the onpressRemove property on the TodoItem component.

...
  renderItem = ({ item, index }) => (
      <TodoItem
        item={item}
        index={index}
        onPressRemove={this.onPressRemove}
      />
    );
 ...

Update our todoItem.js file with the code below.

import React from 'react';
import { Text, View, TouchableHighlight } from 'react-native';
import styles from '../styles/todoItemStyles';
import Icon from 'react-native-vector-icons/FontAwesome';

const TodoItem = ({item, index , onPressRemove}) =>
(
  <View style={styles.container} >
    <Text style={styles.text}
    >{item.title}
    </Text>
    <TouchableHighlight
        onPress={() => onPressRemove(index)}
      >
        <Icon name="remove" size={30} color="#d75452" />
    </TouchableHighlight>
  </View>
);
export default TodoItem;

The TouchableHighlight is a React Native element that enables us to handle touches. The TouchableHighlight React Native element onPress prop takes a function that is called each time it is pressed. The Icon from React-Native-vector-Icons enables use of hundreds of customizable icons in our application.

Save all changes and reload the application. Our application should now look like this. Clicking the remove icon should remove the to-do item.

Screen Shot 2018-01-11 at 6.51.51 PM.png

Marking to-do items as done

Add the method below to the Todo class in src/components/todo.js. This method will change the value of done key of a to-do Item object with a particular index to true or false and update our component's state.

...
 markAsDone = (index) => {
        this.setState(prevState => ({
          todos: prevState.todos.map((item, i) => {
            if (i === index) {
              item.done = !item.done;
              return item;
            }
            return item;
          })
        }));
      }
...

Update the renderItem method in the Todo class in src/components/todo.js to pass the prop markAsDone to the TodoItem component.

...
 renderItem = ({ item, index }) => (
            <TodoItem
              item={item}
              index={index}
              markAsDone={this.markAsDone}
              onPressRemove={this.onPressRemove}
            />
          );
...

Update the todoItem.js with the code below.

src/components/todoItem.js

import React from 'react';
import { Text, View, TouchableHighlight } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import styles from '../styles/todoItemStyles';

const TodoItem = ({
  item, index, onPressRemove, markAsDone
}) =>
  (
    <View style={styles.container} >
      <TouchableHighlight
        onPress={() => markAsDone(index)}
        underlayColor="white"
      >
        { item.done ?
        <Icon name="check-square-o" size={30} color="#5fb660" /> :
        <Icon name="square-o" size={30} color="#808080" />
      }
      </TouchableHighlight>
      <Text style={[
            styles.text, {
              textDecorationLine: item.done ? 'line-through' : 'none',
              color: item.done ? '#808080' : 'black'
          }]}
      >{item.title}
      </Text>
      <TouchableHighlight
        onPress={() => onPressRemove(index)}
      >
        <Icon name="remove" size={30} color="#d75452" />
      </TouchableHighlight>
    </View>
  );

export default TodoItem;

A second TouchableHighlight is added here, which is used to mark a to-do item as done.
There is conditional rendering being used in this component. It renders the check-square-o Icon when the to-do item is marked as done and renders the square-o icon when the to-do item is marked as undone.

The text-decoration and color style property of the todoItem text is also changed based on the status of the done property of the to-do item. When the to-do item is done, the text color is gray and the text-decoration is lined-through, otherwise the text-decoration is none and the text color is black.

Clicking the square-o Icon should mark a to-do item as done and vice versa.

Once done, our final application should look like this.
Screen Shot 2018-01-11 at 7.09.22 PM.png

Conclusion

Our application is now complete! If you have any questions or comments, please add them to the comments section below.
The complete application source code can be viewed here.

Discover and read more posts from Oluwagbenga Joloko
get started
post commentsBe the first to share your opinion
Bittu Singh
6 years ago

hello,
i am an android developer. Now i want to learn react native.
i installed node.js and npm etc. project running successfully but not showing desired output. its showing just “unable to load script from assets ‘index.android.bundle’.” please help me.

Oluwagbenga Joloko
6 years ago

Are you developing on Windows or Mac OS?

What version of react-native are you using?

Have you tried using a new android virtual device or wiping the data from the android virtual device you currently use and restarting it from you AVD manager?

Bittu Singh
6 years ago

m using the window 7 (32 bit).
tried with emulator and physical device also.
but getting same error on both case.

Bittu Singh
6 years ago

can u please share the contact (mobile) number for fast communication.

Show more replies