react-native基础知识以及从零搭建
React native基础React native介绍使用JavaScript和React编写原生移动应用React Native应用是真正的移动应用,React Native产出的并不是“网页应用”, 或者说“HTML5应用”,又或者“混合应用”。 最终产品是一个真正的移动应用,从使用感受上和用Objective-C或Java编写的应用相比几乎是无法区分的。 React Native所使用的基
React native基础
React native介绍
使用JavaScript和React编写原生移动应用
React Native应用是真正的移动应用,React Native产出的并不是“网页应用”, 或者说“HTML5应用”,又或者“混合应用”。 最终产品是一个真正的移动应用,从使用感受上和用Objective-C或Java编写的应用相比几乎是无法区分的。 React Native所使用的基础UI组件和原生应用完全一致。 你要做的就是把这些基础组件使用JavaScript和React的方式组合起来。
中文:https://reactnative.cn/
https://react-native.org.cn/
环境准备
搭建项目框架
expo介绍
模拟测试环境,增强rn开发的能力,提供组件
使用 Expo CLI
假设已安装 Node.js 10 LTS或更高版本,则可以使用npm安装Expo CLI命令行实用程序:
npm install -g expo-cli
或者
yarn global add expo-cli
然后运行以下命令,创建一个名为“rn-basics”本地项目:
expo init rn-basics
cd rn-basics
npm start # 也可以使用命令: expo start
此时会启动一个开发服务器。
运行 React Native 应用程序
在iOS或Android手机上安装[Expo](https://docs.expo.io/versions/v36.0.0/get-started/installation/ Expo)客户端应用程序,并连接到与计算机相同的无线网络(Wifi热点)。在Android上,使用Expo应用程序从终端扫描二维码以打开项目。在iOS上,按照屏幕上的说明(一般为使用相机扫描)获取链接。
修改你的程序
现在你已经成功运行了应用程序,让我们修改一下代码试试。在文本编辑器中打开 App.js 并编辑一些行。保存更改后,应用程序会自动重新加载。
基础知识
React Native 与 React类似,但它使用原生(native)组件而不是基于浏览器(web)组件作为构建块。因此,要了解 React Ntive 应用程序的基本结构,您需要了解一些基本的 React 概念,如JSX、组件、状态和属性。如果你已经了解 React,那么你仍然需要学习一些 React Native 特定的东西,比如 原生(Native) 组件。本教程面向所有人群,无论你是否有 React 经验。
Hello World
编程界的老习惯,先来个 Hello World 尝尝鲜:
import React, { Component } from 'react';
import { Text, View } from 'react-native';
export default class HelloWorldApp extends Component {
render() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Hello, world!</Text>
</View>
);
}
}
如果你感到好奇,这不就是React程序吗?是的,可以直接在web模拟器中运行这段代码。也可以将其粘贴到App.js文件中,以便在本地计算机上创建真正的原生应用程序。
奇葩的语法
这里的一些内容看来可能不像 JavaScript。别慌。这就是未来。
首先,ES2015(也称为ES6)是对JavaScript的一系列改进,ECMAScript 现在是官方标准的一部分,但还没有得到所有浏览器的支持。React Native ships 支持 ES2015,因此你可以使用这些内容而不必担心兼容性。上述示例中的import、from、class 和 extends 都是ES2015的特性。如果你不熟悉ES2015,你也可以通过阅读本教程中的示例代码来了解它。
在这个代码示例中,另一个不寻常的事情是<View><Text>Hello world!</Text></View>。这是JSX——一种在JavaScript中嵌入XML的语法。许多框架使用一种专门的模板语言,允许您在标记语言中嵌入代码。在React中,没有使用模板。JSX允许您在代码中编写标记语言。它看起来像web上的HTML,但这里使用的是React组件,而不是像<div> 或 <span>这样的 HTML 标签。在本例中, <div>或
<span>。
组件
这段代码定义了HelloWorldApp,这是一个新组件。当你在构建一个 React 本地应用程序时,你将大量地生成新组件。你在屏幕上看到的任何东西都是某种组件。
WebView组件
WebView 创建一个原生的 WebView,可以用于访问一个网页。相当于iframe
import { WebView } from "react-native-webview"
Props
大多数组件在创建时都可以使用不同的参数进行自定义。这些创建参数称为props,是properties的缩写。
例如,一个基本的React Native 组件 Image。创建图像时,可以使用名为source的属性来控制它显示的图像。
import React, { Component } from 'react'
import { Image } from 'react-native'
export default class Bananas extends Component {
render() {
let pic = {
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
}
return (
<Image source={pic} style={{width: 193, height: 110}}/>
)
}
}
注意{pic}周围的大括号-它们将变量pic嵌入到JSX中。您可以将任何JavaScript表达式放在JSX中的大括号中。
你自己的组件也可以使用 props。这允许你创建一个在应用程序中的许多不同位置使用的组件,每个组件的属性可以略有不同,获取值可以在渲染函数中引用This.props。下面是一个例子:
import React, { Component } from 'react';
import { Text, View } from 'react-native';
class Greeting extends Component {
render() {
return (
<View style={{alignItems: 'center'}}>
<Text>Hello {this.props.name}!</Text>
</View>
);
}
}
export default class LotsOfGreetings extends Component {
render() {
return (
<View style={{alignItems: 'center', top: 50}}>
<Greeting name='张三' />
<Greeting name='李四' />
<Greeting name='王五' />
</View>
);
}
}
我们在Greeting组件中将name作为一个属性来定制,这样可以复用这一组件来制作各种不同的“问候语”。上面的例子把Greeting组件写在 JSX 语句中,用法和内置组件并无二致——这正是 React 体系的魅力所在——如果你想搭建一套自己的基础 UI 框架,那就放手做吧!
上面的例子出现了一个新的名为 View 的组件。View 常用作其他组件的容器,来帮助控制布局和样式。
仅仅使用 props 和基础的Text、Image 以及 View组件,你就已经足以编写各式各样的 UI 组件了。要学习如何动态修改你的界面,那就需要进一步学习 State(状态)的概念。
State
我们使用两种数据来控制一个组件:props 和 state。props是在父组件中指定,而且一经指定,在被指定的组件的生命周期中则不再改变。对于需要改变的数据,我们需要使用state。
一般来说,你需要在class中声明一个state对象,然后在需要修改时调用setState方法。
假如我们需要制作一段不停闪烁的文字。文字内容本身在组件创建时就已经指定好了,所以文字内容应该是一个prop。而文字的显示或隐藏的状态(快速的显隐切换就产生了闪烁的效果)则是随着时间变化的,因此这一状态应该写到state中。
import React, { Component } from 'react';
import { Text, View } from 'react-native';
class Blink extends Component {
// 声明state对象
state = { isShowingText: true };
componentDidMount() {
// 每1000毫秒对showText状态做一次取反操作
setInterval(() => {
this.setState({
isShowingText: !this.state.isShowingText
});
}, 1000);
}
render() {
// 根据当前showText的值决定是否显示text内容
if (!this.state.isShowingText) {
return null;
}
return (
<Text>{this.props.text}</Text>
);
}
}
export default class BlinkApp extends Component {
render() {
return (
<View>
<Blink text='I love to blink' />
<Blink text='Yes blinking is so great' />
<Blink text='Why did they ever take this out of HTML' />
<Blink text='Look at me look at me look at me' />
</View>
);
}
}
实际开发中,我们一般不会在定时器函数(setInterval、setTimeout 等)中来操作 state。典型的场景是在接收到服务器返回的新数据,或者在用户输入数据之后。你也可以使用一些“状态容器”比如Redux来统一管理数据流。
每次调用setState时,BlinkApp 都会重新执行 render 方法重新渲染。这里我们使用定时器来不停调用setState,于是组件就会随着时间变化不停地重新渲染。
State 的工作原理和 React.js 完全一致,所以对于处理 state 的一些更深入的细节,你可以参阅React.Component API。
提示一些初学者应该牢记的要点:
一切界面变化都是状态state变化
state的修改必须通过setState()方法
this.state.likes = 100; // 这样的直接赋值修改无效!
setState 是一个 merge 合并操作,只修改指定属性,不影响其他属性
setState 是异步操作,修改不会马上生效
处理文本输入
TextInput是一个允许用户输入文本的基础组件。它有一个名为onChangeText的属性,此属性接受一个函数,而此函数会在文本变化时被调用。另外还有一个名为onSubmitEditing的属性,会在文本被提交后(用户按下软键盘上的提交键)调用。
假如我们要实现当用户输入时,实时将其以单词为单位翻译为另一种文字。我们假设这另一种文字来自某个吃货星球,只有一个单词: 🍕。所以"Hello there Bob"将会被翻译为"🍕🍕🍕"。
import React, { Component, useState } from 'react';
import { Text, TextInput, View } from 'react-native';
export default function PizzaTranslator() {
const [text, setText] = useState('');
return (
<View style={{padding: 10}}>
<TextInput
style={{height: 40}}
placeholder="Type here to translate!"
onChangeText={text => setText(text)}
defaultValue={text}
/>
<Text style={{padding: 10, fontSize: 42}}>
{text.split(' ').map((word) => word && '🍕').join(' ')}
</Text>
</View>
);
}
处理触摸事件
移动应用上的用户交互基本靠“摸”。当然,“摸”也是有各种姿势的:在一个按钮上点击,在一个列表上滑动,或是在一个地图上缩放。React Native 提供了可以处理常见触摸手势(例如点击或滑动)的组件, 以及可用于识别更复杂的手势的完整的手势响应系统。
<Button
onPress={() => {
Alert.alert("你点击了按钮!");
}}
title="点我!"
/>
import React, { Component } from 'react';
import { Alert, Button, StyleSheet, View } from 'react-native';
export default class ButtonBasics extends Component {
_onPressButton() {
Alert.alert('You tapped the button!')
}
render() {
return (
<View style={styles.container}>
<View style={styles.buttonContainer}>
<Button
onPress={this._onPressButton}
title="Press Me"
/>
</View>
<View style={styles.buttonContainer}>
<Button
onPress={this._onPressButton}
title="Press Me"
color="#841584"
/>
</View>
<View style={styles.alternativeLayoutButtonContainer}>
<Button
onPress={this._onPressButton}
title="This looks great!"
/>
<Button
onPress={this._onPressButton}
title="OK!"
color="#841584"
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
buttonContainer: {
margin: 20
},
alternativeLayoutButtonContainer: {
margin: 20,
flexDirection: 'row',
justifyContent: 'space-between'
}
})
Touchable 系列组件
https://reactnative.cn/docs/handling-touches
这个组件的样式是固定的。所以如果它的外观并不怎么搭配你的设计 , 那就需要使用TouchableOpacity或是TouchableNativeFeedback组件来定制自己所需要的按钮,视频教程如何制作一个按钮讲述了完整的过程。或者你也可以在 github.com网站上搜索'react native button'来看看社区其他人的作品。
具体使用哪种组件,取决于你希望给用户什么样的视觉反馈:
-
一般来说,你可以使用
TouchableHighlight来制作按钮或者链接。注意此组件的背景会在用户手指按下时变暗。 -
在
Android上还可以使用TouchableNativeFeedback,它会在用户手指按下时形成类似墨水涟漪的视觉效果。 -
TouchableOpacity会在用户手指按下时降低按钮的透明度,而不会改变背景的颜色。 -
如果你想在处理点击事件的同时不显示任何视觉反馈,则需要使用
TouchableWithoutFeedback。
某些场景中你可能需要检测用户是否进行了长按操作。可以在上面列出的任意组件中使用onLongPress属性来实现。
import React, { Component } from 'react';
import { Alert, Platform, StyleSheet, Text, TouchableHighlight, TouchableOpacity, TouchableNativeFeedback, TouchableWithoutFeedback, View } from 'react-native';
export default class Touchables extends Component {
_onPressButton() {
Alert.alert('You tapped the button!')
}
_onLongPressButton() {
Alert.alert('You long-pressed the button!')
}
render() {
return (
<View style={styles.container}>
//此组件的背景会在用户手指按下时变暗。
<TouchableHighlight onPress={this._onPressButton} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>TouchableHighlight</Text>
</View>
</TouchableHighlight>
//会在用户手指按下时降低按钮的透明度,而不会改变背景的颜色
<TouchableOpacity onPress={this._onPressButton}>
<View style={styles.button}>
<Text style={styles.buttonText}>TouchableOpacity</Text>
</View>
</TouchableOpacity>
//会在用户手指按下时形成类似墨水涟漪的视觉效果。
<TouchableNativeFeedback
onPress={this._onPressButton}
background={Platform.OS === 'android' ? TouchableNativeFeedback.SelectableBackground() : ''}>
<View style={styles.button}>
<Text style={styles.buttonText}>TouchableNativeFeedback</Text>
</View>
</TouchableNativeFeedback>
//在处理点击事件的同时不显示任何视觉反馈
<TouchableWithoutFeedback
onPress={this._onPressButton}
>
<View style={styles.button}>
<Text style={styles.buttonText}>TouchableWithoutFeedback</Text>
</View>
</TouchableWithoutFeedback>
<TouchableHighlight onPress={this._onPressButton} onLongPress={this._onLongPressButton} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>Touchable with Long Press</Text>
</View>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
paddingTop: 60,
alignItems: 'center'
},
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3'
},
buttonText: {
textAlign: 'center',
padding: 20,
color: 'white'
}
})
样式
在 React Native 中,你并不需要学习什么特殊的语法来定义样式。我们仍然是使用 JavaScript 来写样式。所有的核心组件都接受名为 style 的属性。这些样式名基本上是遵循了 web 上的 CSS 的命名,只是按照 JS 的语法要求使用了驼峰命名法,例如将 background-color 改为 backgroundColor。
style属性可以是一个普通的 JavaScript 对象。这是最简单的用法,因而在示例代码中很常见。你还可以传入一个数组——在数组中位置居后的样式对象比居前的优先级更高,这样你可以间接实现样式的继承。
实际开发中组件的样式会越来越复杂,我们建议使用 StyleSheet.create 来集中定义组件的样式。比如像下面这样:
import React, { Component } from 'react'
import { StyleSheet, Text, View } from 'react-native'
const styles = StyleSheet.create({
bigBlue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
export default class LotsOfStyles extends Component {
render() {
return (
<View>
<Text style={styles.red}>just red</Text>
<Text style={styles.bigBlue}>just bigBlue</Text>
<Text style={[styles.bigBlue, styles.red]}>bigBlue, then red</Text>
<Text style={[styles.red, styles.bigBlue]}>red, then bigBlue</Text>//使用数组所有的样式都可以生效
</View>
);
}
}
常见的做法是按顺序声明和使用style属性,以借鉴 CSS 中的“层叠”做法(即后声明的属性会覆盖先声明的同名属性)。
宽度(Width) 和 高度(Height)
组件的高度和宽度决定了其在屏幕上显示的尺寸。
指定宽高
最简单的给组件设定尺寸的方式就是在样式中指定固定的 width 和 height。React Native 中的尺寸都是无单位的,表示的是与设备像素密度无关的逻辑像素点。
import React, { Component } from 'react'
import { View } from 'react-native'
export default class FixedDimensionsBasics extends Component {
render() {
return (
<View>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 100, height: 100, backgroundColor: 'skyblue'}} />
<View style={{width: 150, height: 150, backgroundColor: 'steelblue'}} />
</View>
)
}
}
这样给组件设置尺寸也是一种常见的模式,比如要求在不同尺寸的屏幕上都显示成一样的大小。
弹性(Flex)宽高
在组件样式中使用flex可以使其在可利用的空间中动态地扩张或收缩。一般而言我们会使用flex:1来指定某个组件扩张以撑满所有剩余的空间。如果有多个并列的子组件使用了flex:1,则这些子组件会平分父容器中剩余的空间。如果这些并列的子组件的flex值不一样,则谁的值更大,谁占据剩余空间的比例就更大(即占据剩余空间的比等于并列组件间flex值的比)。
组件能够撑满剩余空间的前提是其父容器的尺寸不为零。如果父容器既没有固定的width和height,也没有设定flex,则父容器的尺寸为零。其子组件如果使用了flex,也是无法显示的。
import React, { Component } from 'react'
import { View } from 'react-native'
export default class FlexDimensionsBasics extends Component {
render() {
return (
// 试试去掉父 View 中的`flex: 1`。
// 则父View不再具有尺寸,因此子组件也无法再撑开。
// 然后再用`height: 300` 来代替父 View 的 `flex: 1` 试试看?
<View style={{flex: 1}}>
<View style={{flex: 1, backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
</View>
)
}
}
使用 flexbox 布局
我们在 React Native 中使用 flexbox 规则来指定某个组件的子元素的布局。Flexbox 可以在不同屏幕尺寸上提供一致的布局结构。
一般来说,使用 flexDirection、alignItems 和 justifyContent 三个样式属性就已经能满足大多数布局需求。
React Native 中的 Flexbox 的工作原理和 web 上的 CSS 基本一致,当然也存在少许差异。首先是默认值不同:flexDirection的默认值是column而不是row,而flex也只能指定一个数字值。
Flex
flex 属性决定元素在主轴上如何填满可用区域。整个区域会根据每个元素设置的flex属性值被分割成多个部分。
在下面的例子中,在设置了 flex: 1 的容器view中,有红色,黄色和绿色三个子 view。红色 view 设置了 flex: 1,黄色 view 设置了 flex: 2,绿色 view 设置了 flex: 3。1+2+3 = 6,这意味着红色 view 占据整个区域的 1/6,黄色 view 占据整个区域的 2/6,绿色 view 占据整个区域的3/6。
Flex Direction
在组件的 style 中指定 flexDirection 可以决定布局的主轴。子元素是应该沿着水平轴 (row) 方向排列,还是沿着竖直轴 (column) 方向排列呢?默认值是竖直轴 (column) 方向。
import React, { Component } from 'react'
import { View } from 'react-native'
export default class FlexDirectionBasics extends Component {
render() {
return (
// 尝试把`flexDirection`改为`column`看看
<View style={{flex: 1, flexDirection: 'row'}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
</View>
)
}
}
Layout Direction
布局方向指定层次结构中的子项和文本的布局方向。布局方向也会影响边起点和终点所指的对象。默认情况下,React Native布局使用LTR布局方向。在这种模式下,开始是指左边,结束是指右边。
-
LTR(默认值)文本和子级,并从左到右排列。应用的边距和填充元素的开头应用于左侧。
-
从右到左排列的RTL文本和子项。应用的边距和填充元素的开头应用于右侧。
Justify Content
在组件的 style 中指定 justifyContent 可以决定其子元素沿着主轴的排列方式。子元素是应该靠近主轴的起始端还是末尾段分布呢?亦或应该均匀分布?对应的这些可选项有:flex-start、center、flex-end、space-around、space-between 以及 space-evenly。
import React, { Component } from 'react'
import { View } from 'react-native'
export default class JustifyContentBasics extends Component {
render() {
return (
// 尝试把`justifyContent`改为`center`看看
// 尝试把`flexDirection`改为`row`看看
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'space-between',
}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
</View>
)
}
}
滚动视图
https://reactnative.cn/docs/using-a-scrollview
ScrollView是一个通用的可滚动的容器,你可以在其中放入多个组件和视图,而且这些组件并不需要是同类型的。ScrollView 不仅可以垂直滚动,还能水平滚动(通过horizontal属性来设置)。
长列表
https://reactnative.cn/docs/flatlist
React Native 提供了几个适用于展示长列表数据的组件,一般而言我们会选用FlatList或是SectionList。
FlatList组件用于显示一个垂直的滚动列表,其中的元素之间结构近似而仅数据不同。
FlatList更适于长列表数据,且元素个数可以增删。和ScrollView不同的是,FlatList并不立即渲染所有元素,而是优先渲染屏幕上可见的元素。
FlatList组件必须的两个属性是data和renderItem。data是列表的数据源,而renderItem则从数据源中逐个解析数据,然后返回一个设定好格式的组件来渲染。
下面是一个上拉请求的案例
import React, { Component } from 'react';
import { FlatList, Image, Text, View, StyleSheet,Alert } from 'react-native';
export default class App extends Component {
state = {
data: [],
loaded: false,
limit:10,
page:1,
ismore:true
}
componentDidMount() {
this.fetchData()
}
fetchData() {
fetch(`http://192.168.2.1:9099/coming?_limit=${this.state.limit}&_page=${this.state.page}`).then((response) => response.json())
.then((result) => {
console.log(result.length);
this.setState({
data: this.state.data.concat(result),
loaded: true,
ismore:result.length===this.state.limit?true:false
})
})
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text> loading movies ....</Text>
</View>
)
}
renderMovieItem({ item }) {
return (
<View style={styles.ItemContainer}>
<Image style={styles.img} source={{ uri: item.img.replace('w.h', '100.150') }}></Image>
<View style={styles.rigthContainer}>
<Text>{item.nm}</Text>
</View>
</View>
)
}
render() {
if (!this.state.loaded) {
return this.renderLoadingView()
}
return (
<View style={styles.container}>
<FlatList data={this.state.data}
renderItem={this.renderMovieItem}
onEndReachedThreshold={0.2}
onEndReached={()=>{
console.log('reach end')
if(!this.state.ismore){
Alert.alert('')
Alert.alert(
'提示',
'没有更多的数据了',
[
{text: 'OK', onPress: () => console.log('OK Pressed')},
],
{ cancelable: false }
)
return;
}
this.setState({
page:this.state.page +1
},()=>{
this.fetchData()
})
}}
>
</FlatList>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding:5
// alignItems: "center"
},
ItemContainer: {
flex: 1,
flexDirection: "row",
marginTop:5
},
rigthContainer: {
marginLeft:5,
backgroundColor:'#efefef',
flex: 1
},
img: {
width: 100,
height: 150
}
})
websocket
client
startSocket() {
const ws = new WebSocket('ws://192.168.2.1:8081')
ws.onopen = () => {
ws.send('hello')
}
ws.onmessage = (msg) => {
console.log(msg)
alert(msg.data)
}
ws.onerror =()=>{
}
ws.onclose=()=>{
}
}
server
yarn add ws
const websocket = require('ws');
const ws = new websocket.Server({ port: 8081 })
let clients = {}
let clientname = 0;
ws.on('connection', (client) => {
client.name = ++clientname;
clients[clientname] = client;
client.on('message', (msg) => {
broadcast(client, msg)
})
client.on('close', () => {
delete clients[client.name];
console.log(client.name + '下线了')
})
})
function broadcast(client, msg) {
for (let key in clients) {
clients[key].send(client.name + '说:' + msg)
}
}
特定平台代码
https://reactnative.cn/docs/platform-specific-code
React Native 提供了两种方法来区分平台:
- 使用
Platform模块. - 使用特定平台扩展名.
项目
技术栈: ReactNative,TypeScript,Mobx,expo
expo https://docs.expo.io/
项目搭建:见上面环境搭建流程
1、引入 react-native-tab-navigator
在项目环境命令行里安装 tabbar 导航器,详细内容可参见 react-native-tab-navigator 官网,注意不要忘了安装声明文件
yarn add react-native-tab-navigator -S
yarn add @types/react-native-tab-navigator//声明文件
2、typescript中导入图片,需要使用声明文件
如果像下图这样引入图片文件,ts不会把图片当作一个模块,所以会出现红色的波浪线提示
所以我们需要在根目录创建一个image.d.ts的声明文件,之后再导入图片就可以以模块导入
3、别名配置
yarn add babel-plugin-root-import -D
//bable.config.js
module.exports = function(api) {
api.cache(true);
return {
...
plugins: [
[
"babel-plugin-root-import",
{
rootPathSuffix: "./",
rootPathPrefix: "@/"
}
]
]
};
};
ts.config.js
{
"compilerOptions": {
...
"baseUrl": ".",
"paths": {
"@/*": ["*"]
}
}
}
4、引入样式
rn中是没有css文件的,所以我们需要创建一个js文件来写样式,然后使用的时候导入这个js文件,如果使用的时ts开发的话,js文件引入也是会出现红色的提示,这时候我们可以在tsconfig.json文件中配置允许js
1)使用StyleSheet设置css
定义js文件,使用StyleSheet设置css
引入js文件和expo-device(判断设备类型,得先安装 yarn add expo-device)

使用样式
在tsconfig.json文件中配置允许js
2)使用styled-components

5、组件 Ant-design-mobile-rn 快速上手
https://rn.mobile.ant.design/index-cn
6、拍照
https://docs.expo.io/versions/v38.0.0/sdk/camera/
7、路由
react-navigation
注意 :使用这个插件子组件可以拿到路由信息,但是子子组件拿不到路由信息,这时候我们需要把这个路由信息存到一个属性里,可以使用context组件之间共享信息
8、下拉刷新
https://reactnative.cn/docs/flatlist#onrefresh
使用onRefresh和refreshing
9、分页请求
https://reactnative.cn/docs/flatlist#onendreached
10、微信分享
去微信官方网址https://open.weixin.qq.com/,注册移动应用,填写相关信息,获取到相关到key
其中需要注意到是,安卓需要先生成release包,然后使用 Gen_Signature_Android2.apk 获取到app的签名
安卓app包名地址:android/app/build.gradle文件中的applicationId 字段
打开安卓获取签名软件,输入包名,会得到一个签名,这就是微信SDK需要的一个东西
这里有篇介绍非常详细的文章,流程介绍的很详细:https://www.ahwgs.cn/wechat-rn-share.html
RN具体实现,可以用第三方模块:react-native-wechat, 使用方法参见: https://www.npmjs.com/package/react-native-wechat
打包
expo build:android
expo build:ios
App.json(https://docs.expo.io/workflow/configuration/)
{
"expo": {
"name": "rn-cookbooks",
"slug": "rn-cookbooks",
"platforms": [
"ios",
"android",
"web"
],
"sdkVersion": "37.0.0",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"android": {
"package": "com.qianphone.gp18",
"versionCode": 1
},
"ios": {
"bundleIdentifier": "com.qianphone.gp18"
}
}
}
总结
- 开发rn的环境是expo
- rn和react的差异
- 样式基于flex布局 ,flex布局主轴方向是垂直的, 样式没有单位
- websocket
- 常用组件(长列表等)
- ant-design组件库
- 状态管理:mobx(也可以用其他状态管理工具)
- mobx优点:简单
- mobx-react中的inject和observer可以依据mobx中可观察状态对组件进行更新
- 打包的时候项目不要关闭,要不然不会成功
更多推荐


所有评论(0)