使用 React Native 1 的聊天应用 - 使用 react-native-paper 构建可重复使用的 UI 表单元素
今年,React Native 社区经历了诸多变化。从社区对 React Hooks 的适配开始,到官方文档新增了域名,再到最受欢迎的库之一react-navigation
采用更动态、更基于组件的方式向应用添加路由,最后,react-native-firebase
使用 Firebase SDK 的首选软件包也发布了第六个版本,并进行了一些改进。
在本教程系列中,我将使用前面描述的所有最新版本的包来展示如何在 2020 年使用 React Native 构建应用程序。您将在学习过程中学到很多关于这些库的知识,并构建一个聊天应用程序。
本教程旨在帮助您熟悉 React Native 及其常用库(例如react-navigation
和)的所有最新更新react-native-firebase
。如果您希望添加本教程未涵盖的新功能,请随意添加,并按照自己的节奏进行学习。
要求
以下要求将确保您拥有合适的开发环境:
- 上面的 Node.js
10.x.x
安装在你的本地机器上 - JavaScript/ES6 基础知识
- watchman 文件监视程序已安装
react-native-cli
通过 npm 安装或通过 npx 访问react-navigation
Firebase
项目react-native-firebase
react-native-paper
有关如何为 React Native 设置开发环境的完整演练,您可以查看此处的官方文档。
另外,请注意,以下教程将使用 react-native 版本0.61.5
。请确保您使用的 React Native 版本高于0.60.x
。
安装库
首先,创建一个新的 React Native 项目并按照以下步骤安装库。您需要打开一个终端窗口来执行此过程。
npx react-native init ChatApp
# navigate inside the project directory
cd ChatApp
# install following libraries for navigationOptions
yarn add @react-navigation/native @react-navigation/stack react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view react-native-paper react-native-vector-icons
安装依赖项后,请确保按照其官方文档中的说明配置其本机二进制文件,以使其与 React Native 一起工作。
这些说明将来可能会发生变化,因此最好遵循官方文档。
iOS 用户,请确保在必要时通过cocoapods安装 pods 。
创建可重复使用的表单元素
在本节中,我们将创建一些可重用的表单组件,例如FormInput
和FormButton
。这些 UI 组件将在两个屏幕中使用:登录和注册。
这些可重复使用的表单组件带来的优势是您不必为两个屏幕组件一遍又一遍地编写相同的通用代码。
在此 React Native 应用程序的根目录下,创建一个名为 的新目录src/
,并在其中创建一个名为 的新目录components/
。
在此目录中,创建一个名为 的新文件FormInput.js
。该组件将为屏幕组件提供一个文本输入字段,供用户输入凭据。
首先导入以下语句。
import React from 'react';
import { StyleSheet, Dimensions } from 'react-native';
import { TextInput } from 'react-native-paper';
Dimensions
来自 React Native 核心 API,提供了一种获取屏幕宽度和高度的方法。无需为文本输入字段提供固定的宽度和高度,只需让此 API 为我们计算即可。您可以通过添加以下代码片段来获取应用程序的屏幕和高度。
const { width, height } = Dimensions.get('screen');
FormInput
接下来,导出将具有一些道具的默认函数。
export default function FormInput({ labelName, ...rest }) {
return (
<TextInput
label={labelName}
style={styles.input}
numberOfLines={1}
{...rest}
/>
);
}
该...rest
props 必须是作为参数传递的最后一个 prop,否则会报错。传递此 prop 的目的是允许组件拥有其他 props 的值。
最后,为这个可重用组件定义相应的样式。
const styles = StyleSheet.create({
input: {
marginTop: 10,
marginBottom: 10,
width: width / 1.5,
height: height / 15
}
});
下一个可重用组件将位于一个名为的单独文件中FormButton.js
。它与 类似,FormInput
只是该组件将用于在屏幕上显示一个按钮。
它还将使用Dimensions
React Native 的屏幕宽度和高度。
以下是完整的代码片段:
import React from 'react';
import { StyleSheet, Dimensions, Text } from 'react-native';
import { Button } from 'react-native-paper';
const { width, height } = Dimensions.get('screen');
export default function FormButton({ title, modeValue, ...rest }) {
return (
<Button
mode={modeValue}
{...rest}
style={styles.button}
contentStyle={styles.buttonContainer}
>
{title}
</Button>
);
}
const styles = StyleSheet.create({
button: {
marginTop: 10
},
buttonContainer: {
width: width / 2,
height: height / 15
}
});
UI库react-native-paper
有三种模式来显示按钮。
text
:没有背景或轮廓的扁平按钮outlined
:带有轮廓的按钮contained
:具有背景颜色和高程阴影的按钮
针对不同的目的,您将使用不同的按钮模式。稍后您将在屏幕组件中看到它们。因此,最好将值作为 prop 来接受(如上面的代码片段所述modeValue
:)。
创建登录屏幕
要在当前应用中实现屏幕,首先要创建名为 的最基本屏幕LoginScreen
。当用户未经身份验证或授权进入应用并使用其功能时,这将是初始路径。
这是您将在本节中实现的屏幕的演示。
在 中src/
,创建另一个名为 的目录screens/
。我们将在此目录中存储所有屏幕组件。在其中,同样创建LoginScreen.js
。
登录屏幕将有四个主要的 UI 元素:
- 两个用于输入用户电子邮件和密码的文本输入字段
- 一个登录按钮和一个导航到注册屏幕的按钮(以防最终用户未注册使用该应用程序)
首先导入以下语句。
import React, { useState } from 'react';
import { View, StyleSheet } from 'react-native';
import { Title } from 'react-native-paper';
import FormInput from '../components/FormInput';
import FormButton from '../components/FormButton';
在功能组件内部LoginScreen
,定义两个状态变量:
email
password
这两个变量都将与FormInput
组件一起使用,以获取用户凭证的值。默认情况下,它们的值将为空字符串。
export default function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
return (
<View style={styles.container}>
<Title style={styles.titleText}>Welcome to Chat app</Title>
<FormInput
labelName='Email'
value={email}
autoCapitalize='none'
onChangeText={userEmail => setEmail(userEmail)}
/>
<FormInput
labelName='Password'
value={password}
secureTextEntry={true}
onChangeText={userPassword => setPassword(userPassword)}
/>
<FormButton
title='Login'
modeValue='contained'
labelStyle={styles.loginButtonLabel}
/>
<FormButton
title='New user? Join here'
modeValue='text'
uppercase={false}
labelStyle={styles.navButtonText}
/>
</View>
);
}
请注意,每个元素FormInput
都会传递不同的 props。例如,电子邮件组件设置autoCaptialize
为none
。密码组件secureTextEntry
设置为布尔值 true 。对于其他元素,这很有...rest
用(正如您在上一节中看到的)。
该onChangeText
prop 接受一个回调,每当输入字段的文本发生变化时就会调用该回调。
最后,这是样式。
const styles = StyleSheet.create({
container: {
backgroundColor: '#f5f5f5',
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
titleText: {
fontSize: 24,
marginBottom: 10
},
loginButtonLabel: {
fontSize: 22
},
navButtonText: {
fontSize: 16
}
});
请注意,到目前为止,您都在使用 JavaScript 对象来定义每个组件的样式。React StyleSheet
Native 提供了一个 API,用于在组件文件中创建样式。它像上面一样接受一个 JavaScript 对象,并Stylesheet
从中返回一个新对象。React Native 中没有像 Web 开发中那样的类或ID。要创建新的样式对象,请使用StyleSheet.create()
方法。
通过创建对象来定义样式是首选方法。它不仅可以帮助您组织样式并保持样式的独立性,而且以这种方式定义的样式也只需通过原生渲染桥发送一次(与内联样式不同)。
创建注册屏幕
如果用户尚未注册使用该应用程序,但想要创建一个新帐户来获得授权,那么注册屏幕就变得有用。
SignupScreen.js
在目录中创建一个名为inside的新文件src/screens/
。它将在很多方面与您在上一节中创建的登录屏幕相似。我将留给您自己去发现这两个屏幕之间的异同。请查看下面注册屏幕的代码片段。
import React, { useState } from 'react';
import { View, StyleSheet } from 'react-native';
import { Title, IconButton } from 'react-native-paper';
import FormInput from '../components/FormInput';
import FormButton from '../components/FormButton';
export default function SignupScreen({ navigation }) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
return (
<View style={styles.container}>
<Title style={styles.titleText}>Register to chat</Title>
<FormInput
labelName='Email'
value={email}
autoCapitalize='none'
onChangeText={userEmail => setEmail(userEmail)}
/>
<FormInput
labelName='Password'
value={password}
secureTextEntry={true}
onChangeText={userPassword => setPassword(userPassword)}
/>
<FormButton
title='Signup'
modeValue='contained'
labelStyle={styles.loginButtonLabel}
/>
<IconButton
icon='keyboard-backspace'
size={30}
style={styles.navButton}
color='#6646ee'
onPress={() => navigation.navigate('Login')}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#f5f5f5',
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
titleText: {
fontSize: 24,
marginBottom: 10
},
loginButtonLabel: {
fontSize: 22
},
navButtonText: {
fontSize: 18
},
navButton: {
marginTop: 10
}
});
上述组件代码片段的主要区别在于,您将使用一个按钮IconButton
从注册屏幕导航到登录屏幕。该按钮由 提供react-native-paper
,实际上是一个显示图标的按钮,没有任何标签。
创建身份验证堆栈导航器
当前应用中将有两个堆栈导航器。第一个导航器将被称为AuthStack
。
它将仅包含允许用户添加凭据或创建凭据的屏幕。因此,登录屏幕和注册屏幕将作为路由,其中登录屏幕将转到初始路由。稍后您将了解有关第二个堆栈的更多信息。
创建一个新目录src/navigation/
。该目录将包含在应用中构建导航所需的所有路由和其他必要组件。
在此目录中,创建一个名为 的新文件AuthStack.js
。此文件将包含一个堆栈导航器。
首先导入包含两个屏幕组件的以下语句。
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import SignupScreen from '../screens/SignupScreen';
import LoginScreen from '../screens/LoginScreen';
Stack Navigator为 React Native 应用提供了在不同屏幕之间切换的功能,类似于 Web 浏览器中的导航。在导航状态下,它会推送或弹出屏幕。
接下来,创建一个堆栈导航器的实例,如下所示。
const Stack = createStackNavigator();
导航器使用 的 5.0 版本以声明方式定义react-navigation
。它遵循一种更加基于组件的方法,类似于react-router
使用 React.js 进行 Web 开发的 (如果你熟悉的话)。
这createStackNavigator
是一个用于实现堆栈导航模式的函数。此函数返回两个 React 组件:Screen
和Navigator
,它们帮助我们配置每个组件的屏幕,如下所示。
export default function AuthStack() {
return (
<Stack.Navigator initialRouteName='Login' headerMode='none'>
<Stack.Screen name='Login' component={LoginScreen} />
<Stack.Screen name='Signup' component={SignupScreen} />
</Stack.Navigator>
);
}
接受Stack.Navigator
每个屏幕路由共有的 prop 值。例如,堆栈导航器通常会为其内部的每个屏幕添加一个标题。对于当前堆栈,您不需要在每个屏幕上都添加标题。因此,设置headerMode
为 的值即可none
满足要求。
该headerMode
属性指定了堆栈中每个屏幕的标题应如何渲染。将其设置为none
,则表示完全不渲染标题。您可以在此处找到此模式的其他值。
这initialRouteName
是导航器第一次加载时呈现的路线的名称。
您可以在此处的帖子中了解更多 Stack Navigator 及其常见属性。
为了使登录到注册屏幕之间的导航正常工作,您必须navigation
向每个组件添加 prop。转到LoginScreen.js
文件并将navigation
prop 引用作为参数传递。
export default function LoginScreen({ navigation }) {
// ...
}
此 prop 引用提供了一组可作为每个屏幕组件操作的函数。请注意,您只能将作为导航器路由的屏幕组件传递给它。
例如,在登录屏幕组件中,要导航到注册屏幕,请将onPress
prop 添加到最后一个FormButton
。navigation.navigate
从当前屏幕,接受要导航到的屏幕的值。
<FormButton
title='New user? Join here'
modeValue='text'
uppercase={false}
labelStyle={styles.navButtonText}
onPress={() => navigation.navigate('Signup')}
/>
同样,打开SignupScreen.js
screen文件,并传递prop引用navigation
。
export default function SignupScreen({ navigation }) {
// ...
}
接下来,将onPress
道具添加到IconButton
。
<IconButton
icon='keyboard-backspace'
size={30}
style={styles.navButton}
color='#6646ee'
onPress={() => navigation.goBack()}
/>
该goBack()
操作关闭活动屏幕(注册屏幕)并移回堆栈(登录屏幕)。
有关该道具的更多信息,请查看此处的navigation
官方参考。
添加导航容器
现在,我们的两个屏幕组件都已配置完毕,可以正常导航了。在本节中,我们将添加缺失的部分,NavigationContainer
以确保身份验证堆栈中的当前导航能够正常工作。
Routes.js
创建一个名为inside目录的新文件src/navigation/
。该文件将包含应用程序将拥有的所有堆栈,但目前仅包含身份验证堆栈。
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import AuthStack from './AuthStack';
export default function Routes() {
return (
<NavigationContainer>
<AuthStack />
</NavigationContainer>
);
}
这NavigationContainer
是一个管理导航树的组件。它还允许屏幕组件引用navigation
prop 引用。这是通过包装所有导航器结构来实现的。
与纸张供应商一起包装
创建一个名为index.js
insidesrc/navigation/
目录的文件。
为了使 UI 组件能够react-native-paper
工作,您必须将所有路由包装在里面,PaperProvider
如下所示。
import React from 'react';
import { Provider as PaperProvider } from 'react-native-paper';
import Routes from './Routes';
/**
* Wrap all providers here
*/
export default function Providers() {
return (
<PaperProvider>
<Routes />
</PaperProvider>
);
}
该PaperProvider
组件为框架中的所有组件提供主题。它还充当需要在顶层渲染的组件的门户。
这是必需的步骤。之所以要创建一个单独的Providers
组件Routes
并包装App
它(正如官方文档中提到的),是因为这个应用稍后会用到一些自定义的提供程序。因此,为了管理所有提供程序,最好创建一个单独的文件。
结论
屏幕组件的表单现已完成。为了确保它们能够正常工作,请打开终端窗口并针对特定的移动平台构建应用程序。
# for ios
npx react-native run-ios
# for android
npx react-native run-android
然后,进入模拟器,您将获得以下结果。
下一步是什么?
在本教程系列的第一部分中,您已成功使用 react-navigation 库构建了导航流,设置了堆栈导航器,并学习了如何使用 react-navtive-paper 中的预定义 UI 组件来创建可重复使用的自定义表单组件。
在本系列的下一部分中,我们将学习如何安装 Firebase SDK,如何为 iOS 应用生成和添加 Firebase 凭据和 API 密钥,如何用 Firebase 实现电子邮件登录提供程序,以及如何将导航流程与实时后端服务结合使用。
您可以在此 Github repo中找到该项目的完整源代码。
👉 以下是本教程中使用的资源列表。
- 详细了解
navigation prop reference
Dimensions
React Native 中的 API- 点击此处开始使用
react-navigation
v5 的堆栈导航器
💙 要了解有关 React Native 的更多信息,请查看以下资源:
最初发表于Heartbeat.Fritz.Ai。
文章来源:https://dev.to/amanhimself/chat-app-with-react-native-1-build-reusable-ui-form-elements-using-react-native-paper-1h4j