Skip to content

Commit

Permalink
Add example of connecting a Realm React app to sync (#4356)
Browse files Browse the repository at this point in the history
* Add an example of connecting a Realm React app to sync
* Generate JS app
* Enable flexible sync
* Refactor Templates
favor const over function for components
favor named exports over default exports
apply sync configuration at the index.js
separate sync and non-sync apps for readability
remove the anon login flow
move the sync setup steps into their own document
create example app that is lerna aware
create sync script to transmit example app source into all other templates
update versions of realm/react and realm
default template version to 0.0.1
favor type over interface
wrap all in component function declarations in useCallback
generate realm context in the index.ts of the models folder

Co-authored-by: Andrew Meyer <andrew.meyer@mongodb.com>
  • Loading branch information
Tom Duncalf and takameyer committed Apr 1, 2022
1 parent b6c3668 commit 2aea89b
Show file tree
Hide file tree
Showing 183 changed files with 6,229 additions and 4,556 deletions.
2 changes: 1 addition & 1 deletion .eslintignore
Expand Up @@ -14,6 +14,6 @@ vendor/
/integration-tests/
/install-tests/
/packages/
/examples/
/tests/ReactTestApp/
/templates/
/example/
File renamed without changes.
File renamed without changes.
4 changes: 4 additions & 0 deletions example/.eslintrc.js
@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: '@react-native-community',
};
File renamed without changes.
Expand Up @@ -28,6 +28,7 @@ build/
.gradle
local.properties
*.iml
*.hprof

# node.js
#
Expand Down
7 changes: 7 additions & 0 deletions example/.prettierrc.js
@@ -0,0 +1,7 @@
module.exports = {
bracketSpacing: false,
jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
arrowParens: 'avoid',
};
1 change: 1 addition & 0 deletions example/.watchmanconfig
@@ -0,0 +1 @@
{}
45 changes: 45 additions & 0 deletions example/README.md
@@ -0,0 +1,45 @@
# React Native Template Realm TypeScript

## Usage

Simple React Native template to quickly get started with Realm.

This app implements a simple todo list, using Realm for persistence and the [Realm React](https://github.com/realm/realm-js/tree/master/packages/realm-react) hooks for React integration. It supports sync, allowing users to login and sync their todo lists across multiple devices.

## 🚀 How to use

```
npx lerna bootstrap --scope=realm-example --include-dependencies
```

## 🏃 How to build and run locally

- [Setup React Native development Environment](https://reactnative.dev/docs/environment-setup)
- Build/Run on iOS 🍎
```
npm run ios
```
- Build/Run on Android 🤖
```
npm run android
```

## 💻 Start the Dev Client

```
npm start
```

## 💾 Testing changes to the template when developing

To test the template locally, run it like any other React Native app: `npm i && npx pod-install` then `npm run ios`.

## 🔀 Setting up sync

See https://github.com/realm/realm-js/blob/master/templates/docs/sync-setup.md for instructions.
## 📝 Notes
- [React Native docs](https://reactnative.dev/docs/getting-started)
- [React Hooks](https://reactjs.org/docs/hooks-intro.html)
- [Setting Up Realm Sync](https://docs.mongodb.com/realm/sdk/react-native/quick-start/)
- [Realm JS Documentation](https://docs.mongodb.com/realm/sdk/react-native/)
- [@realm/react Readme](https://github.com/realm/realm-js/tree/master/packages/realm-react#readme)
14 changes: 14 additions & 0 deletions example/__tests__/App-test.tsx
@@ -0,0 +1,14 @@
/**
* @format
*/

import 'react-native';
import React from 'react';
import {AppWrapperNonSync} from '../app/AppWrapperNonSync';

// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';

it('renders correctly', () => {
renderer.create(<AppWrapperNonSync />);
});
Expand Up @@ -35,12 +35,12 @@ android_library(

android_build_config(
name = "build_config",
package = "com.realmreactexample",
package = "com.realmtstemplate",
)

android_resource(
name = "res",
package = "com.realmreactexample",
package = "com.realmtstemplate",
res = "src/main/res",
)

Expand Down
Expand Up @@ -120,13 +120,18 @@ def jscFlavor = 'org.webkit:android-jsc:+'
*/
def enableHermes = project.ext.react.get("enableHermes", false);

/**
* Architectures to build native code for in debug.
*/
def nativeArchitectures = project.getProperties().get("reactNativeDebugArchitectures")

android {
ndkVersion rootProject.ext.ndkVersion

compileSdkVersion rootProject.ext.compileSdkVersion

defaultConfig {
applicationId "com.realmreactexample"
applicationId "com.realmtstemplate"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
Expand All @@ -151,6 +156,11 @@ android {
buildTypes {
debug {
signingConfig signingConfigs.debug
if (nativeArchitectures) {
ndk {
abiFilters nativeArchitectures.split(',')
}
}
}
release {
// Caution! In production, you need to generate your own keystore file.
Expand Down Expand Up @@ -186,7 +196,7 @@ dependencies {
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"

debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
exclude group:'com.facebook.fbjni'
}

debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Expand Up @@ -4,7 +4,7 @@
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.realmreactexample;
package com.realmtstemplate;

import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
Expand Down
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.realmreactexample">
package="com.realmtstemplate">

<uses-permission android:name="android.permission.INTERNET" />

Expand Down
@@ -1,4 +1,4 @@
package com.realmreactexample;
package com.realmtstemplate;

import com.facebook.react.ReactActivity;

Expand All @@ -10,6 +10,6 @@ public class MainActivity extends ReactActivity {
*/
@Override
protected String getMainComponentName() {
return "RealmReactExample";
return "RealmTsTemplate";
}
}
@@ -1,4 +1,4 @@
package com.realmreactexample;
package com.realmtstemplate;

import android.app.Application;
import android.content.Context;
Expand Down Expand Up @@ -62,7 +62,7 @@ private static void initializeFlipper(
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.realmreactexample.ReactNativeFlipper");
Class<?> aClass = Class.forName("com.realmtstemplate.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
Expand Down
3 changes: 3 additions & 0 deletions example/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
<resources>
<string name="app_name">RealmTsTemplate</string>
</resources>
Expand Up @@ -3,7 +3,6 @@
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:textColor">#000000</item>
</style>

</resources>
Expand Up @@ -6,14 +6,14 @@ buildscript {
minSdkVersion = 21
compileSdkVersion = 30
targetSdkVersion = 30
ndkVersion = "20.1.5948944"
ndkVersion = "21.4.7075529"
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:4.2.1")
classpath("com.android.tools.build:gradle:4.2.2")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
Expand Down
Expand Up @@ -25,4 +25,4 @@ android.useAndroidX=true
android.enableJetifier=true

# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.93.0
FLIPPER_VERSION=0.99.0
File renamed without changes.
File renamed without changes.
@@ -1,3 +1,3 @@
rootProject.name = 'RealmReactExample'
rootProject.name = 'RealmTsTemplate'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'
4 changes: 4 additions & 0 deletions example/app.json
@@ -0,0 +1,4 @@
{
"name": "RealmTsTemplate",
"displayName": "RealmTsTemplate"
}
15 changes: 15 additions & 0 deletions example/app/AppNonSync.tsx
@@ -0,0 +1,15 @@
import React, {useMemo} from 'react';

import {Task} from './models/Task';
import {TaskRealmContext} from './models';
import {TaskManager} from './components/TaskManager';

const {useQuery} = TaskRealmContext;

export const AppNonSync = () => {
const result = useQuery(Task);

const tasks = useMemo(() => result.sorted('createdAt'), [result]);

return <TaskManager tasks={tasks} />;
};
26 changes: 26 additions & 0 deletions example/app/AppSync.tsx
@@ -0,0 +1,26 @@
import React, {useEffect, useMemo} from 'react';

import {Task} from './models/Task';
import {TaskRealmContext} from './models';
import {TaskManager} from './components/TaskManager';

const {useRealm, useQuery} = TaskRealmContext;

type AppProps = {
userId: string;
};

export const AppSync: React.FC<AppProps> = ({userId}) => {
const realm = useRealm();
const result = useQuery(Task);

const tasks = useMemo(() => result.sorted('createdAt'), [result]);

useEffect(() => {
realm.subscriptions.update(mutableSubs => {
mutableSubs.add(result);
});
}, [realm, result]);

return <TaskManager tasks={tasks} userId={userId} />;
};
26 changes: 26 additions & 0 deletions example/app/AppWrapperNonSync.tsx
@@ -0,0 +1,26 @@
import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';

import {TaskRealmContext} from './models';
import colors from './styles/colors';
import {AppNonSync} from './AppNonSync';

export const AppWrapperNonSync = () => {
const {RealmProvider} = TaskRealmContext;

// If sync is disabled, setup the app without any sync functionality and return early
return (
<SafeAreaView style={styles.screen}>
<RealmProvider>
<AppNonSync />
</RealmProvider>
</SafeAreaView>
);
};

const styles = StyleSheet.create({
screen: {
flex: 1,
backgroundColor: colors.darkBlue,
},
});

0 comments on commit 2aea89b

Please sign in to comment.