Introduction
When working with React Native applications, managing local data efficiently is crucial. Realm is a high-performance mobile database that offers a seamless experience for data storage and retrieval. In this blog, we will explore how to integrate Realm into a React Native project using @realm/react to create, read, update, and delete data.
Setting Up the Project
To get started, install the necessary dependencies:
yarn add realm @realm/react
Implementing Realm in React Native
1. Wrapping the App with RealmProvider
To integrate Realm, wrap the entire app with RealmProvider. This ensures that the database schema is accessible throughout the application.
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { RealmProvider } from '@realm/react';
import CreateScreen from './screens/CreateScreen';
import { Person } from './models/Person';
import { Car } from './models/Car';
import { Address } from './models/Address';
const Tab = createBottomTabNavigator();
const App = () => {
return (
<RealmProvider deleteRealmIfMigrationNeeded schema={[Person, Car, Address]}>
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Create" component={CreateScreen} />
</Tab.Navigator>
</NavigationContainer>
</RealmProvider>
);
};
export default App;
2. Understanding deleteRealmIfMigrationNeeded
The deleteRealmIfMigrationNeeded option in Realm is a setting that allows developers to automatically delete the existing Realm database if a schema change is detected. This is useful during development when frequent schema changes occur, preventing migration-related crashes.
3. Defining and Joining Database Models
Realm operates with schemas that define the structure of stored data. Let's create models for Person, Car, and Address and see how they are joined.
Person Model
import { Realm } from 'realm';
export class Person extends Realm.Object {
static schema = {
name: 'Person',
primaryKey: '_id',
properties: {
_id: 'objectId',
name: 'string',
age: 'int?',
date: {
type: 'date',
default: () => new Date(),
},
cars: {
type: 'list',
objectType: 'Car',
},
address: 'Address',
},
};
}
Car Model
import { Realm } from 'realm';
export class Car extends Realm.Object {
static schema = {
name: 'Car',
primaryKey: '_id',
properties: {
_id: 'objectId',
c_name: 'string',
c_color: 'string',
date: {
type: 'date',
default: () => new Date(),
},
},
};
}
Address Model
import { Realm } from 'realm';
export class Address extends Realm.Object {
static schema = {
name: 'Address',
embedded: true,
properties: {
country: 'string?',
},
};
}
How Schemas Are Joined in Realm
Realm supports relationships between objects. In our case:
- The
Personmodel has a one-to-many relationship withCar(carsis an array ofCarobjects). - The
Personmodel has a one-to-one relationship withAddress(addressis a singleAddressobject). -
Embedded objects, like
Address, are stored directly inside their parent object rather than being separate entries in the database.
When creating a Person entry, you can assign multiple Car objects and an Address object, effectively linking them together.
Example of creating a Person with related Car and Address:
realm.write(() => {
const car1 = realm.create('Car', { _id: new Realm.BSON.ObjectID(), c_name: 'Toyota Camry', c_color: 'Red' });
const car2 = realm.create('Car', { _id: new Realm.BSON.ObjectID(), c_name: 'Honda Accord', c_color: 'Blue' });
realm.create('Person', {
_id: new Realm.BSON.ObjectID(),
name: 'John Doe',
age: 30,
cars: [car1, car2],
address: { country: 'USA' },
});
});
Usage
import { Realm } from 'realm';
import { useObject, useQuery, useRealm } from '@realm/react';
import React, { useState } from 'react';
import {
View,
TextInput,
Button,
StyleSheet,
FlatList,
Text,
ScrollView,
TouchableOpacity,
} from 'react-native';
import { Person } from '../models/Person';
import { Car } from '../models/Car';
const CreateScreen = () => {
const realm = useRealm();
const persons = useQuery(Person); // to get all list in array
// const myTask = useObject(Task, _id); // to get specific item.object
const cars = useQuery(Car);
const [userName, setUserName] = useState('');
const [age, setAge] = useState('');
const handleUserNameChange = (text) => {
setUserName(text);
};
const handleAgeChange = (text) => {
setAge(+text);
};
const addSampleCars = () => {
realm.write(() => {
realm.create('Car', {
_id: new Realm.BSON.ObjectID(),
c_name: 'Toyota Camry',
c_color: 'Red',
});
realm.create('Car', {
_id: new Realm.BSON.ObjectID(),
c_name: 'Honda Accord',
c_color: 'Blue',
});
realm.create('Car', {
_id: new Realm.BSON.ObjectID(),
c_name: 'Ford Mustang',
c_color: 'Yellow',
});
});
};
const handleSubmit = () => {
addSampleCars();
realm.write(() => {
realm.create('Person', {
_id: new Realm.BSON.ObjectID(),
name: userName,
age,
cars,
address: {
country: 'India',
},
});
});
setUserName('');
setAge('');
};
const onPressDelete = (item) => {
realm.write(() => {
realm.delete(item);
});
};
const onPressItem = (person) => {
realm.write(() => {
// Retrieve the person object using the primary key
const userToUpdate = realm.objectForPrimaryKey('Person', person._id);
// Increment the age by 1
if (userToUpdate) {
userToUpdate.age += 1;
}
});
/* 1. FINDING EXAMPLE BASED ON QUERY
// filter for tasks that have just-started or short-running progress
const lowProgressTasks = useQuery(Task, tasks => {
return tasks.filtered(
'$0 <= progressMinutes && progressMinutes < $1',
1,
10,
);
});
// retrieve the set of Task objects
const tasks = useQuery(Task);
// Sort tasks by name in ascending order
const tasksByName = useQuery(Task, tasks => {
return tasks.sorted('name');
});
// Sort tasks by name in descending order
const tasksByNameDescending = useQuery(Task, tasks => {
return tasks.sorted('name', true);
});
// Sort tasks by priority in descending order and then by name alphabetically
const tasksByPriorityDescendingAndName = useQuery(Task, tasks => {
return tasks.sorted([
['priority', true],
['name', false],
]);
});
// Sort Tasks by Assignee's name.
const tasksByAssigneeName = useQuery(Task, tasks => {
return tasks.sorted('assignee.name');
});
*/
/**
* 2. UPDATE OR INSERT EG.
realm.write(() => {
// Add a new Task to the realm. Since no task with ID 1234
// has been added yet, this adds the instance to the realm.
myTask = realm.create(
'Task',
{_id: 1234, name: 'Wash the car', progressMinutes: 0},
'modified',
);
// If an object exists, setting the third parameter (`updateMode`) to
// "modified" only updates properties that have changed, resulting in
// faster operations.
myTask = realm.create(
'Task',
{_id: 1234, name: 'Wash the car', progressMinutes: 5},
'modified',
);
});
*/
};
console.log('personspersonspersons', JSON.stringify(persons));
return (
<View style={{ alignItems: 'center', flex: 1, justifyContent: 'center' }}>
<ScrollView style={styles.container}>
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
placeholder="Enter your name"
value={userName}
onChangeText={handleUserNameChange}
/>
<TextInput
style={styles.input}
placeholder="Enter your age"
value={age}
onChangeText={handleAgeChange}
keyboardType="numeric"
/>
<Button title="Add User" onPress={handleSubmit} />
</View>
<FlatList
data={persons}
scrollEnabled={false}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => onPressItem(item)} style={styles.userItem}>
<Text>{item.name}</Text>
<Text>{item.age}</Text>
<Text onPress={() => onPressDelete(item)} style={{ fontWeight: 'bold' }}>
X
</Text>
</TouchableOpacity>
)}
keyExtractor={(item, index) => index.toString()}
/>
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 10,
},
inputContainer: {
marginBottom: 20,
},
input: {
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 5,
padding: 10,
marginBottom: 10,
width: 200,
},
list: {
alignItems: 'center',
},
userItem: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 5,
padding: 10,
marginBottom: 10,
width: '90%',
},
});
export default CreateScreen;
Summary
In this blog, we covered:
-
Setting up Realm with
@realm/react -
Understanding
deleteRealmIfMigrationNeededfor handling schema changes -
Defining and joining schemas (
Person,Car,Address) - Using relationships to structure data effectively
- Implementing CRUD operations to manage local data
- Understanding embedded objects for optimal schema design
Realm simplifies database management in React Native, making it a powerful choice for applications requiring offline capabilities and real-time performance. Start integrating it into your projects today!
Top comments (0)