react-native基础知识以及从零搭建

React native基础

React native介绍

使用JavaScript和React编写原生移动应用

React Native应用是真正的移动应用,React Native产出的并不是“网页应用”, 或者说“HTML5应用”,又或者“混合应用”。 最终产品是一个真正的移动应用,从使用感受上和用Objective-C或Java编写的应用相比几乎是无法区分的。 React Native所使用的基础UI组件和原生应用完全一致。 你要做的就是把这些基础组件使用JavaScript和React的方式组合起来。

英文官网:https://reactnative.dev/

中文:https://reactnative.cn/
https://react-native.org.cn/

环境准备

搭建项目框架

expo介绍

http://expo.io

模拟测试环境,增强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,你也可以通过阅读本教程中的示例代码来了解它。

在这个代码示例中,另一个不寻常的事情是Hello world!。这是JSX——一种在JavaScript中嵌入XML的语法。许多框架使用一种专门的模板语言,允许您在标记语言中嵌入代码。在React中,没有使用模板。JSX允许您在代码中编写标记语言。它看起来像web上的HTML,但这里使用的是React组件,而不是像

这样的 HTML 标签。在本例中, 是一个内置组件,它显示一些文本,类似于

组件

这段代码定义了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 和基础的TextImage 以及 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)

组件的高度和宽度决定了其在屏幕上显示的尺寸。

指定宽高

最简单的给组件设定尺寸的方式就是在样式中指定固定的 widthheight。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 可以在不同屏幕尺寸上提供一致的布局结构。

一般来说,使用 flexDirectionalignItemsjustifyContent 三个样式属性就已经能满足大多数布局需求。

React Native 中的 Flexbox 的工作原理和 web 上的 CSS 基本一致,当然也存在少许差异。首先是默认值不同:flexDirection的默认值是column而不是row,而flex也只能指定一个数字值。

Flex

flex 属性决定元素在主轴上如何填满可用区域。整个区域会根据每个元素设置的flex属性值被分割成多个部分。

在下面的例子中,在设置了 flex: 1 的容器view中,有红色,黄色和绿色三个子 view。红色 view 设置了 flex: 1,黄色 view 设置了 flex: 2,绿色 view 设置了 flex: 31+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组件必须的两个属性是datarenderItemdata是列表的数据源,而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的声明文件,之后再导入图片就可以以模块导入
react-native基础知识以及从零搭建_第1张图片

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
react-native基础知识以及从零搭建_第2张图片

引入js文件和expo-device(判断设备类型,得先安装 yarn add expo-device

在这里插入图片描述

使用样式
react-native基础知识以及从零搭建_第3张图片

tsconfig.json文件中配置允许js
react-native基础知识以及从零搭建_第4张图片

2)使用styled-components

react-native基础知识以及从零搭建_第5张图片

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

https://reactnavigation.org/

注意 :使用这个插件子组件可以拿到路由信息,但是子子组件拿不到路由信息,这时候我们需要把这个路由信息存到一个属性里,可以使用context组件之间共享信息

8、下拉刷新

https://reactnative.cn/docs/flatlist#onrefresh
使用onRefreshrefreshing

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"
    }
  }
}

总结

  1. 开发rn的环境是expo
  2. rn和react的差异
  3. 样式基于flex布局 ,flex布局主轴方向是垂直的, 样式没有单位
  4. websocket
  5. 常用组件(长列表等)
  6. ant-design组件库
  7. 状态管理:mobx(也可以用其他状态管理工具)
  8. mobx优点:简单
  9. mobx-react中的inject和observer可以依据mobx中可观察状态对组件进行更新
  10. 打包的时候项目不要关闭,要不然不会成功

你可能感兴趣的:(react,native)