Expo Router + Supabase使用流程

unsetunset前言unsetunset

Expo是一个React-native生态中的一个工具包,提供了非常多的功能,Expo Router是Expo最近推出的功能,其效果类似于Nextjs的router,可以基于目录结构来实现路由。 Supabase是一个开源的postgres数据库,还带有用户体系功能,可以快速实现login、register这些功能。

我将记录一下,我使用这2个工具,构建基础基础IOS APP的流程。

本文不是手把手教程。

unsetunset项目搭建unsetunset

请阅读expo文档:https://docs.expo.dev/router/installation/#quick-start

注意,我这里使用的是expo router的文档,而不是expo的文档,因为单独使用expo也可以构建APP,而我们需要使用expo router,简化我们APP的路由设计。

我们将使用当前最新的expo 50和expo router 3.0来构建项目骨架,按下面的命令,一行行执行则可:

npx create-expo-appyarnnpx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-barnpx expo install react-native-web react-dom

在app.json中,添加如scheme和bundler:

{"scheme": "your-app-scheme","web": {"bundler": "metro"}
}
f7594518dbdc69fd2703d225fff76e73.png

弄好后,直接yarn start启动项目,然后点击【i】,通过IOS simulator(IOS模拟器)打开项目。

8bb452f8e735009aabb045372aa212a7.png

unsetunset开发Tabs结构unsetunset

首先,你需要了解一下目录对应路由的基本概念:https://docs.expo.dev/router/create-pages/,然后开始写代码。

首先,在package.json中,修改main,使用expo-router的入口逻辑:

{"main": "expo-router/entry"
}

这样,expo就会使用根目录下app文件夹中的index.js作为入口文件了,而App.js就没有用了,可以删掉。

我们创建app/index.js,写入如下代码:

// app/index.js
import { Text } from 'react-native';export default function Page() {return <Text>Home page</Text>;
}

你可以安装下图插件。e2e2e327cd909ef2d8ef297e162bda8f.png

然后使用rnfes,快速构建页面模版d6a7f73d09a5fcb6ce3ac70dfdd1a33b.png

等待expo刷新一下,就可以从模拟器看见Home page字样了,如果等了一会,没有看见,代码也确定没有问题,就退出一下expo,跟在iphone强退应用一样的操作。

然后,我们来写tabs的具体逻辑。

在(tabs)目录中创建home与settings目录,然后在home与settings目录下,分别创建_layout.js和index.js,因为写法相同,所以以home目录为例,_layout.js和index.js代码如下:

// app/(tabs)/home/index.jsimport { Stack } from "expo-router";
import { Text, View } from "react-native";export default function Home() {return (<View>// 设置页面 title的<Stack.Screen options={{ headerShown: true, title: "Ayuliao Page Title" }} /><Text>Index page of Home Tab</Text></View>);
}
// app/(tabs)/home/_layout.js
import { Stack } from "expo-router";export default function HomeLayout() {return <Stack />;
}

上面代码,使用了expo-router中的Stack,正如其名,它的作用就是创建一个页面,然后用户访问新页面时,会像栈一样操作它,具体而言,访问新页面时,入栈,返回时,出栈,这样,返回页面时,就会回到上一个页面,当然Stack提供了replace操作,替换当前页面,这样返回时,当前页面就没了,一会我们做auth时,会用。

更多,可以阅读:https://docs.expo.dev/router/navigating-pages/

然后,我们需要在(tabs)目录下创建_layout.js文件,用来定义tabs,关于expo-router tabs可以阅读:https://docs.expo.dev/router/advanced/tabs ,这里贴出相关的代码:

// app/(tabs)/_layout.jsimport { Tabs } from "expo-router";
import { Entypo, Ionicons } from '@expo/vector-icons';export default function TabsLayout() {return (<Tabs screenOptions={{ headerShown: false }}><Tabs.Screenname="home"options={{tabBarIcon: ({ color }) => <Entypo name="home" size={20} color={color} />,}}/><Tabs.Screenname="settings"options={{tabBarIcon: ({ color }) => <Ionicons name="settings" size={20} color={color} />,}}/></Tabs>);
}

这样,我们就实现了tabs,这里有一个细节,就是使用了icon,我们需要安装相关的库:

yarn add @expo/vector-icons

然后在这个网页中https://icons.expo.fyi/Index,搜索需要的icon,比如home的icon,然后就可以直接使用了,非常方便。

1c9fd559f378250d84dce5e952e77f0b.png

至此tabs功能就实现了。为了体验一下Stack切换页面时,可以切回上一页的效果,我这里,在settings中加一个Link调整,然后在app/(tabs)/home中创建page2.js,然后让settings页调到page2.js页,修改后的settings index.js代码如下:

import { Link, Stack } from "expo-router";
import { Text, View } from "react-native";export default function Page() {return (<View><Stack.Screen options={{ headerShown: true, title: "Settings" }} /><Text>Index page of Settings Tab 2</Text>// 跳转页面<Link href={"/home/page2"} style={{ marginTop: 16 }}><Text style={{ fontWeight: "bold" }}>Go To Page2</Text></Link></View>);
}

效果如下:

98687936d1804d5da1cf86d5216480d5.pngc9b71417857dc3f37d822998fac62cfe.png

df830f9fc0e7c157acaa4cdf4e319303.png
从settings跳转后,可以home页面页

这里,你可能的一个疑惑是,为什么从settings页面跳过去的page2,返回时,是跳回home页?

这是因为,page2.js跟home的index.js都在home目录下,一个目录,是一个栈的结构,所以会是上面的效果。

unsetunsetAuth逻辑unsetunset

先安装相关的依赖库:

yarn add @supabase/supabase-js
yarn add react-native-elements @react-native-async-storage/async-storage react-native-url-polyfill
npx expo install expo-secure-store

我们只需要参考expo和supabase相关的文档,就可以实现登录的效果。

首先,我们在创建app/lib/supabase-client.js文件,代码如下:

// app/lib/supabase-client.jsimport 'react-native-url-polyfill/auto'
import * as SecureStore from 'expo-secure-store'
import { createClient } from '@supabase/supabase-js'const ExpoSecureStoreAdapter = {getItem: (key) => {return SecureStore.getItemAsync(key)},setItem: (key, value) => {SecureStore.setItemAsync(key, value)},removeItem: (key) => {SecureStore.deleteItemAsync(key)},
}const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL
const supabaseAnonKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEYexport const supabase = createClient(supabaseUrl, supabaseAnonKey, {auth: {storage: ExpoSecureStoreAdapter,autoRefreshToken: true},
})

获得supabase对象,用户auth数据存到expo-secure-store中,环境变量写在根目录的.env文件中,使用EXPO_开头。

然后,我们创建(auth)目录,然后创建login.js文件,写入如下代码:

// app/(auth)/login.jsimport React, { useState } from "react";
import { Alert, StyleSheet, TextInput, View, Button, Text } from "react-native";
import { supabase } from "../lib/supabase-client";
import { GestureHandlerRootView, TouchableOpacity } from "react-native-gesture-handler";
import { Stack } from "expo-router";export default function AuthPage() {const [email, setEmail] = useState("");const [password, setPassword] = useState("");const [loading, setLoading] = useState(false);async function signInWithEmail() {setLoading(true);const { error } = await supabase.auth.signInWithPassword({email: email,password: password,});if (error) {Alert.alert("Sign In Error", error.message);} else {Alert.alert("sign In Success")}setLoading(false);}async function signUpWithEmail() {setLoading(true);const { error } = await supabase.auth.signUp({email: email,password: password,});if (error) {Alert.alert("Sign Up Error", error.message);} else {Alert.alert('Sign Up Finish')}setLoading(false);}return (<GestureHandlerRootView style={styles.container}><Stack.Screen options={{ headerShown: true, title: "Supabase Expo Router App" }} /><View style={[styles.verticallySpaced, styles.mt20]}><TextInputstyle={styles.textInput}label="Email"onChangeText={(text) => setEmail(text)}value={email}placeholder="email@address.com"autoCapitalize={"none"}/></View><View style={styles.verticallySpaced}><TextInputstyle={styles.textInput}label="Password"onChangeText={(text) => setPassword(text)}value={password}secureTextEntry={true}placeholder="Password"autoCapitalize={"none"}/></View><View style={[styles.verticallySpaced, styles.mt20]}><TouchableOpacitydisabled={loading}onPress={() => signInWithEmail()}style={styles.buttonContainer}><Text style={styles.buttonText}>SIGN IN</Text></TouchableOpacity></View><View style={styles.verticallySpaced}><TouchableOpacitydisabled={loading}onPress={() => signUpWithEmail()}style={styles.buttonContainer}><Text style={styles.buttonText}>SIGN UP</Text></TouchableOpacity></View></GestureHandlerRootView>);
}

这里,有个细节,就是我们使用了react-native-gesture-handler库的TouchableOpacity来实现触控点击效果。TouchableOpacity需要在GestureHandlerRootView布局下才可被使用。

因为TouchableOpacity与react-native原生的Pressable功能似乎相似,所以在刚接触时,我就有点疑惑两者的区别。

react-native-gesture-handler库它直接与原生手势系统集成,提供更接近原生性能的触摸反馈,从而可以提供更流畅的用户体验。而Pressable使用JavaScript线程来处理触摸事件,多数情况下,是够用的,除非出现复杂的手势需求。

简单总结:简单用例,可以用Pressable,你不需要安装第三方库,而复杂的手势处理和对性能有要求的,就用TouchableOpacity,这里,我统一使用TouchableOpacity来处理所有触摸点击需求。

然后,我们需要修改一下index.js,让没有登录的用户重定向到login页面。

// app/index.jsimport { router } from "expo-router";
import { useEffect } from "react";
import { supabase } from "./lib/supabase-client";console.log('supabase obj: ', supabase)export default function IndexPage() {useEffect(() => {supabase.auth.getSession().then(({ data: { session } }) => {// 如果获取不到session,表明用户没有登录if (session) {router.replace("/(tabs)/home/");} else {console.log("no user");}});// 用户登录状态变化supabase.auth.onAuthStateChange((_event, session) => {if (session) {router.replace("/(tabs)/home/");} else {console.log("no user");router.replace("/(auth)/login");}});}, []);}

运行起来后,会获得如下效果

1037c980add723ada42d870af4e674d0.png

然后成功登录后

80e11457aaa3ecedf0bf8639d0914ebb.png

unsetunset结尾unsetunset

相关代码:https://github.com/ayuLiao/expo-router-supabase

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/461361.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

yolov8自制数据训练集

目录 1.YOLOv8是啥 2.系统环境 3.安装labelimg 3.1安装 3.2启动 labelimg 4.自制分类图片 4.1 YOLO数据集要求 4.2 图片保存目录 4.3 利用labelimg进行标注 4.4 存储图片 4.5 标注文件 5.数据集训练 5.1yaml文件 5.2训练命令 5.3查看训练过程 5.3.1启动tensorb…

Android AOSP源码研究之万事开头难----经验教训记录

文章目录 1.概述2.Android源下载1.配置环境变量2.安装curl3.下载repo并授权4.创建一个文件夹保存源码5.设置repo的地址并配置为清华源6.初始化仓库7.指定我们需要下载的源码分支并初始化 2.1 使用移动硬盘存放Android源码的坑2.2 解决方法 3.Android源码编译4.Android源烧录 1.…

element ui表格手写拖动排序

效果图&#xff1a; 思路&#xff1a; 重点在于&#xff1a;拖动行到某一位置&#xff0c;拿到这一位置的标识&#xff0c;数据插入进这个位置 vueuse的拖拽hooks useDraggable 可以用&#xff1b;html5 drag能拖动行元素&#xff1b;mounsedown、mounsemove时间实现拖拽 页…

JavaScript基础第六天

JavaScript 基础第六天 今天我们学习数组的遍历&#xff0c;以及数组的其他用法。 1. 数组遍历 1.1. 古老方法 可以使用 for 循环进行遍历。 let arr ["a", "b", "d", "g"]; for (let i 0; i < arr.length; i) {console.log…

火星文:网络时代下的语言

引言 在互联网时代&#xff0c;网络语言的发展日新月异。火星文作为一种特殊的网络表达方式&#xff0c;近年来逐渐兴起并成为了网络文化的一部分。 火星文生成器 | 一个覆盖广泛主题工具的高效在线平台(amd794.com) https://amd794.com/huoxingwen 火星文的兴起时代 火星…

了解物联网漏洞与家庭网络入侵之间的联系

我们的家庭正日益成为一个由互连设备组成的网络。从智能恒温器到联网冰箱&#xff0c;物联网 (IoT) 彻底改变了我们与家庭环境互动的方式。 随着技术进步带来了新的挑战&#xff1a;这些设备容易受到网络威胁以及随之而来的家庭网络入侵风险。 在这篇博文中&#xff0c;我们将…

JCIM | MD揭示PTP1B磷酸酶激活RtcB连接酶的机制

Background 内质网应激反应&#xff08;UPR&#xff09; 中的一个重要过程。UPR是由内质网中的三种跨膜传感器&#xff08;IRE1、PERK和ATF6&#xff09;控制的细胞应激反应&#xff0c;当内质网中的蛋白质折叠能力受到压力时&#xff0c;UPR通过减少蛋白质合成和增加未折叠或错…

基础图算法与社交网络分析

目录 前言1 寻找最短路径的Dijkstra算法1.1 介绍1.2 算法步骤1.3 应用领域1.4 算法优势与限制 2 构建高效网络结构的最小生成树算法2.1 Kruskal算法2.2 应用领域2.3 算法优势与限制 3 中心度算法3.1 PageRank算法3.2 Degree Centrality&#xff08;度中心度&#xff09;3.3 Bet…

项目02《游戏-12-开发》Unity3D

基于 项目02《游戏-11-开发》Unity3D &#xff0c; 任务&#xff1a;实现场景怪物自动巡航 &#xff0c; 首先在场景中创建小球命名为路径点WayPoint0&#xff0c; 取消小球的碰撞器Collider&#xff0c; 再复制两个改名为WayPoint1 和 WayPoint2 &#xff0c; 在…

Kubernetes基础(十五)-k8s网络通信

1 k8s网络类型 2 Pod网络 2.1 同一pod内不同容器通信 Pod是Kubernetes中最小的可部署单元&#xff0c;它是一个或多个紧密关联的容器的组合&#xff0c;这些容器共享同一个网络命名空间和存储卷&#xff0c;因此Pod中的所有容器都共享相同的网络命名空间和IP地址——PodIP&a…

LabVIEW网络测控系统

LabVIEW网络测控系统 介绍了基于LabVIEW的网络测控系统的开发与应用&#xff0c;通过网络技术实现了远程的数据采集、监控和控制。系统采用LabVIEW软件与网络通信技术相结合&#xff0c;提高了系统的灵活性和扩展性&#xff0c;适用于各种工业和科研领域的远程测控需求。 随着…

《动手学深度学习(PyTorch版)》笔记7.6

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过&…