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
Person
model has a one-to-many relationship withCar
(cars
is an array ofCar
objects). - The
Person
model has a one-to-one relationship withAddress
(address
is a singleAddress
object). -
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
deleteRealmIfMigrationNeeded
for 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)