Skip to content

Commit

Permalink
Add react native tutorial, fix some mistakes found along the way
Browse files Browse the repository at this point in the history
  • Loading branch information
Vincent (Wen Yu) Ge committed Apr 7, 2024
1 parent af0bd5c commit 39f47ad
Show file tree
Hide file tree
Showing 17 changed files with 718 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/routes/docs/tutorials/android/step-1/+page.markdoc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ This tutorial will introduce the following concepts:
2. Authentication
3. Databases and collections
4. Queries and pagination
5. Storage


# Prerequisites {% #prerequisites %}
1. Basic knowledge of Kotlin and Android development.
Expand Down
10 changes: 10 additions & 0 deletions src/routes/docs/tutorials/react-native/+layout.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script lang="ts">
import { globToTutorial } from '$lib/utils/tutorials.js';
import { setContext } from 'svelte';
export let data;
const tutorials = globToTutorial(data);
setContext('tutorials', tutorials);
</script>

<slot />
11 changes: 11 additions & 0 deletions src/routes/docs/tutorials/react-native/+layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { LayoutLoad } from './$types';

export const load: LayoutLoad = ({ url }) => {
const tutorials = import.meta.glob('./**/*.markdoc', {
eager: true
});
return {
tutorials,
pathname: url.pathname
};
};
6 changes: 6 additions & 0 deletions src/routes/docs/tutorials/react-native/+page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { redirect } from '@sveltejs/kit';
import type { PageLoad } from './$types';

export const load: PageLoad = async () => {
redirect(303, '/docs/tutorials/react/step-1');
};
28 changes: 28 additions & 0 deletions src/routes/docs/tutorials/react-native/step-1/+page.markdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
layout: tutorial
title: Build an ideas tracker with React Native
description: Learn to build a React Native app with no backend code using an Appwrite backend.
step: 1
difficulty: beginner
readtime: 10
category: Mobile and native
framework: React Native
---

**Idea tracker**: an app to track all the side project ideas that you'll start, but probably never finish.
In this tutorial, you will build Idea tracker with Appwrite and React Native.

# Concepts {% #concepts %}

This tutorial will introduce the following concepts:

1. Setting up your first project
2. Authentication
3. Databases and collections
4. Queries and pagination

# Prerequisites {% #prerequisites %}

1. Android, iOS simulators, or a physical device to run the app
2. Have [Node.js](https://nodejs.org/en) and [NPM](https://www.npmjs.com/) installed on your computer
3. Basic knowledge of React Native and Expo
43 changes: 43 additions & 0 deletions src/routes/docs/tutorials/react-native/step-2/+page.markdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
layout: tutorial
title: Create app
description: Create a React Native app project and integrate with Appwrite.
step: 2
---

# Create React Native project {% #create-react-project %}

Create a React Native app with the `npm create` command.

```sh
npx create-expo-app ideas-tracker
cd ideas-tracker
```

# Add dependencies {% #add-dependencies %}

Install the React Native Appwrite SDK.

```sh
npx expo install react-native-appwrite react-native-url-polyfill
```

Then, install React Navigation to help implement simple navigation logic.

```sh
npm install @react-navigation/native @react-navigation/native-stack
```

Install peer dependencies needed for React Navigation.

```sh
npx expo install react-native-screens react-native-safe-area-context
```

For iOS with bare React Native project, make sure you have CocoaPods installed. Then install the pods to complete the installation:

```
cd ios
pod install
cd ..
```
60 changes: 60 additions & 0 deletions src/routes/docs/tutorials/react-native/step-3/+page.markdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
layout: tutorial
title: Set up Appwrite
description: Import and initialize Appwrite for your React Native application.
step: 3
---

# Create project {% #create-project %}

Head to the [Appwrite Console](https://cloud.appwrite.io/console).

{% only_dark %}
![Create project screen](/images/docs/quick-starts/dark/create-project.png)
{% /only_dark %}
{% only_light %}
![Create project screen](/images/docs/quick-starts/create-project.png)
{% /only_light %}

If this is your first time using Appwrite, create an account and create your first project.

Then, under **Add a platform**, add a **Android** or **Apple** platform with the package/bundle ID `com.example.idea-tracker`.

{% only_dark %}
![Add a platform](/images/docs/quick-starts/dark/add-platform.png)
{% /only_dark %}
{% only_light %}
![Add a platform](/images/docs/quick-starts/add-platform.png)
{% /only_light %}

You can skip optional steps.

# Initialize Appwrite SDK {% #init-sdk %}

To use Appwrite in our React Native app, you'll need to find our project ID.
Find your project's ID in the **Settings** page.

{% only_dark %}
![Project settings screen](/images/docs/quick-starts/dark/project-id.png)
{% /only_dark %}
{% only_light %}
![Project settings screen](/images/docs/quick-starts/project-id.png)
{% /only_light %}

Create a new file `lib/appwrite.js` to hold our Appwrite related code.
Only one instance of the `Client()` class should be created per app.
Add the following code to it, replacing `<YOUR_PROJECT_ID>` with your project ID.

```js
import { Client, Databases, Account } from "react-native-appwrite";

const client = new Client();
client
.setEndpoint("https://cloud.appwrite.io/v1")
.setProject("<YOUR_PROJECT_ID>") // Replace with your project ID
.setPlatform('com.example.idea-tracker');


export const account = new Account(client);
export const databases = new Databases(client);
```
166 changes: 166 additions & 0 deletions src/routes/docs/tutorials/react-native/step-4/+page.markdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
---
layout: tutorial
title: Add authentication
description: Add authentication to your React Native application.
step: 4
---

# User context {% #user-context %}

In React Native, you can use [context](https://reactjs.org/docs/context.html) to share data between components.
You can use a context and a custom hook to manage our user's data.

Create a new file `contexts/UserContext.jsx` and add the following code to it.

```js
import { ID } from "react-native-appwrite";
import { createContext, useContext, useEffect, useState } from "react";
import { account } from "../lib/appwrite";
import { toast } from "../lib/toast";


const UserContext = createContext();

export function useUser() {
return useContext(UserContext);
}

export function UserProvider(props) {
const [user, setUser] = useState(null);

async function login(email, password) {
const loggedIn = await account.createEmailSession(email, password);
setUser(loggedIn);
toast('Welcome back. You are logged in');
}

async function logout() {
await account.deleteSession("current");
setUser(null);
toast('Logged out');
}

async function register(email, password) {
await account.create(ID.unique(), email, password);
await login(email, password);
toast('Account created');
}

async function init() {
try {
const loggedIn = await account.get();
setUser(loggedIn);
toast('Welcome back. You are logged in');
} catch (err) {
setUser(null);
}
}

useEffect(() => {
init();
}, []);

return (
<UserContext.Provider value={{ current: user, login, logout, register, toast }}>
{props.children}
</UserContext.Provider>
);
}
```

Now, you can use the `useUser` hook to access the user's data from any component wrapped by this context's provider.

# Display toasts {% #display-toasts %}

For a better user experience, display toasts when the users perform an action, such as login, logout, create new ideas, etc.

We can do this by creating a new file `lib/toast.js` and adding the following code to it.

```js
import { ToastAndroid, Platform, AlertIOS } from 'react-native';

export function toast(msg) {
if (Platform.OS === 'android') {
ToastAndroid.show(msg, ToastAndroid.SHORT)
} else {
AlertIOS.alert(msg);
}
}
```
# Login page {% #login-page %}

Create a new file `views/Login.jsx` and add the following code to it.
this page contains a basic form to allow the user to login or register.
Notice how this page consumes the `useUser` hook to access the user's data and perform login and register actions.

```js
import React, { useState } from 'react';
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';
import { useUser } from '../contexts/UserContext';


export default function LoginScreen() {
const user = useUser();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
return (
<View style={styles.container}>
<Text style={styles.header}>Login or register</Text>
<TextInput
style={styles.input}
placeholder="Email"
value={email}
onChangeText={setEmail}
/>
<TextInput
style={styles.input}
placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry
/>
<View style={styles.buttonContainer}>
<Button
title="Login"
onPress={
() => {
user.login(email, password)
}
}
/>
<Button
title="Register"
onPress={
() => {
user.register(email, password)
}
}
/>
</View>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
padding: 16,
},
header: {
fontSize: 24,
marginBottom: 20,
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 10,
paddingLeft: 8,
},
buttonContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
},
});
```
Loading

0 comments on commit 39f47ad

Please sign in to comment.