React Native 系列(二)

前言

本系列是基于React Native版本号0.44.3写的,最初学习React Native的时候,完全没有接触过ReactJS,本文的目的是为了给那些JSReact小白提供一个快速入门,让你们能够在看React Native语法的时候不那么费劲,有过前端开发经验的可以直接忽略。

什么是React

React是一个JavaScript框架,用来开发web应用。Web应用开发中,比较流行的有三个框架:

  • react
  • angular
  • vue

从名字上,就能看到react native是基于React(都是Facebook出品)。React的设计思想是:

  • Declarative(交互式的)

    应用都是基于状态的,应用会随着数据的变化切换到不同的状态,React
    将这种状态抽象为一个个View,这样状态改变后,利用React就在不同
    View之间切换。这样,让代码更清晰可预测,也方便测试。

  • Component-Based(基于组件的)

    把管理状态的View封装成Component,然后再把这些Component
    组合到一起来实现复杂的UI

  • Learn Once, Write Anywhere(一次编写,多处编译)

    React支持Web开发,Server开发(Node),同样也支持本文提到的App开发(React Native)。

JSX

JSXJavaScript语言的扩展,它并不改变JS本身语法。使用起来类型XMLReact会对JSX的代码进行编译,生成JavaScript代码,用来描述React中的Element如何渲染。

上篇文章创建的项目中,index.ios.js里面的这段代码就是JSX语法:

render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
      </View>
    );
  }

其中,

<Text style={styles.welcome}>
    Welcome to React Native!
</Text>

会被编译成

React.createElement(
    Text,
    {style: styles.welcom},
    ‘Welcome to React Native!‘
)

注意:使用JSX,一定要在scope中,能够访问到React和对应的Element。比如刚刚的例子,在代码的最上面看到了这样的import

import React, { Component } from ‘react‘;
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
    TouchableHighlight
} from ‘react-native‘;

tips: jsx编译结果在线查看
如果你的标签是空的,可以用/>进行close,比如:
<CustomComponent style={styles.welcome} />

大小写

JSX对大小写开头是敏感的

  • 小写字母开头会被认为是html内置的标签。比如div
  • 大写字母开头会被认为是自己创建的或者importcomponent

所以,自定义的component必须是大写字母开头

举个??:
如果上文中的Text改成小写,

<text style={styles.welcome}>
    Welcome to React Native!
</text>

会被编译成:

React.createElement(
    "text",
    { style: styles.welcome },
    "Welcome to React Native!"
);

React在解析的时候,会认为这和div类似,是html内置标签,引起错误。

JS代码

JSX中的JS表达式要用{}括起来,不要加引号,加引号后React会认为是字符串。
比如,你可以这么写:

<Text style={styles.welcome}>
    {"Welcome" + "to" + "React Native"}
</Text>

Children

根据以下的代码:

<View style={styles.container}>
    <Text style={styles.welcome}>
        Welcome to React Native!
    </Text>
</View>

可以看出,在JSX中可以嵌套Element形成一种层次结构,这种层次结构可以动态生成,例如:

render() {
    var textElement = <Text style={styles.welcome}>{mainText}</Text>

    return (
        <View style={styles.container}>
          {textElement}
        </View>
    );
  }

Element

Element是你在屏幕上想看到的东西,在React中,一个element就是一个对象。

React中,element是不变的。如果用户想要看到变化,就需要渲染下一帧。

那么你可能会问,这样效率不是很低么?

事实上,React只会更新变化的部分,对于不变的视图,是不会重新渲染的。

React强调函数式编程,不可变状态是函数式编程的核心思想之一。不可变状态能够让你的代码更容易编写,测试和维护。一个不可变的函数,在输入一定的时候,输出一定是一样的。

Component

React Native开发中,component是一个非常重要的概念,它类似于iOSUIView或者Android中的view,将视图分成一个个小的部分。
React Native中,我们通常采用ES6 class来定义一个Component

比如上面的代码:

export default class Hello extends Component {
    render(){
        // ...
    }
}

其中,render()是实际的渲染函数,通常,使用JSX来返回想要看到的视图。
React Native中的Component都是原生的Component,通过JS bridge来调用原生的Component来渲染。
这些Component分为两种:

  1. iOS/Android通用的,比如:NavigatorTextImage等等;
  2. 平台独有的,比如:NavigatorIOSProgressBarAndroid等等;

State/props

ReactComponent有两个内置参数对象

  • props,由React自动初始化,包含了传递给一个Component的参数。
  • state,包含的参数对象应当用在render函数中,用作渲染。调用this.setState()会触发上文提到的Component重新渲染。

初始化

比如,我们对本文代码进行修改,新建一个Component:

class Scott extends Component {
  render(){
    return (
        <Text style={styles.welcome}>
            欢迎来到{this.props.name}博客学习RN
        </Text>
    );
  }
}

然后,我们使用这个自定义的Component

export default class Hello extends Component {
  render() {
    return (
        <View style={styles.container}>
            <Scott name={"scott"}/>
        </View>
    );
  }
}

保存文件,选中模拟器,command + R刷新一下,就能看到如下界面:

通过这个例子,如何对Component初始化进行传值就已经很清楚了:

  • <Scott name={"scott"}/>初始化的时候,通过JSX的参数来传值
  • Scott内部,通过this.props.name来访问这个值

修改视图状态

React中,修改视图状态是通过this.setState触发render重新调用,进而修改视图状态。

我们继续修改上述代码,添加一个构造函数,对state进行初始化,然后在Scott初始化的时候,通过this.state.name获取到值。
在最上面的import中,我们导入TouchableOpacity,然后在点击事件中,我们调用this.setState更新显示的文字:

export default class Hello extends Component {

  // 构造
  constructor(props) {
    super(props);
    // 初始状态
    this.state = {name: "Jack"};
  }

  _onPressText(){
    this.setState({name: "scott"})
  }

  render() {
    return (
        <View style={styles.container}>
          <TouchableOpacity onPress={() => this._onPressText()}>
            <Scott name={this.state.name}/>
          </TouchableOpacity>
        </View>
    );
  }
}

保存,选中模拟器,command + R刷新一下,点击屏幕文字,效果如下:

setState 注意事项

  • 不要直接修改state

    这样并不会触发重新渲染:
    this.setState.name = "scott"

  • setState修改可能是异步的

    React有可能会对多个this.setState进行收集,然后一起更新UI。所以,不要直接依赖上一个状态的结果。所以,这样是不对的:

    this.setState({
        counter: this.state.counter + this.props.number
    });

    如果要依赖于上一个状态,使用this.setState第二个模式:

    this.setState(function(prevState, props){
        return {
            counter: prevState.counter + props.number
        };
    });
  • setState是增量更新

    比如:

    class Scott extends Component {
        render(){
            return (
                <Text style={styles.welcome}>
                    点击注意看Lucy是否变成Scott:
                    {this.props.name}
                </Text>
            );
        }
    }
    
    export default class Hello extends Component {
    
        // 构造
        constructor(props) {
            super(props);
            // 初始状态
            this.state = {firstName:"Lucy", lastName:"Tom"};
        }
    
        _onPressText(){
            this.setState({firstName:"Scott"})
        }
    
        render() {
            return (
                <View style={styles.container}>
                    <TouchableOpacity onPress={() => this._onPressText()}>
                        <Scott name={this.state.firstName + this.state.lastName}/>
                    </TouchableOpacity>
                </View>
            );
        }
    }

    可以看到,点击文字之后,通过

    this.setState({firstName:"Scott"})

    只是修改了firstNamelastName没有做任何变化。

    tips: 上文的 onPress采用了js中的箭头函数,除了箭头函数之外,也可以用function本身传入:

    export default class Hello extends Component {
    
        // 构造
        constructor(props) {
            super(props);
            // 初始状态
            this.state = {firstName:"Lucy", lastName:"Tom"};
            this._onPressText = this._onPressText.bind(this);
        }
    
        _onPressText(){
            this.setState({firstName:"Scott"})
        }
    
        render() {
            return (
                <View style={styles.container}>
                    <TouchableOpacity onPress={this._onPressText}>
                        <Scott name={this.state.firstName + this.state.lastName}/>
                    </TouchableOpacity>
                </View>
            );
        }
    }

    注意这一行:

    this._onPressText = this._onPressText.bind(this);

    因为JS中,class的函数默认没有bind。需要调用bind来把this传入_onPressText

组件生命周期

  • 任何一个组件都是有生命周期的,我们经常需要在组件的生命周期中做一些事情,比如创建组件的时候或者组件销毁的时候。
  • 组件生命周期大致分为三个阶段,实例化阶段,运行阶段,销毁阶段。

创建阶段

  • constructor

    • 什么时候调用:在组件初始化的时候调用
    • 作用:初始化state
  • componentWillMount
    • 什么时候调用:即将加载组件的时候调用
    • 作用:在render之前做事情
  • render
    • 什么时候调用:渲染组件的时候调用
    • 作用:通过这个方法渲染界面
  • componentDidMount
    • 什么时候调用:组件渲染完成之后调用
    • 作用:在render之后做事情,比如发送请求

tip:**注意点constructorcomponentWillMountcomponentDidMount只会调用一次**

更新阶段

  • componentWillReceiveProps

    • 什么时候调用:每次传入Props的时候就会调用
    • 作用:拦截Props
  • shouldComponentUpdate
    • 什么时候调用:每次Props或者State改变就会调用
    • 作用:控制界面是否刷新
  • componentWillUpdate
    • 什么时候调用:组件即将更新的时候调用
    • 作用:在render更新前做事情
  • componentDidUpdate
    • 什么时候调用:组件更新完成之后调用
    • 作用:在render更新后做事情

tips:注意点:绝对不要在componentWillUpdatecomponentDidUpdate中调用this.setState方法,否则将导致无限循环调用,在componentWillReceivePropsshouldComponentUpdate可以。

销毁阶段

  • componentWillUnmount

    • 什么时候调用:组将即将销毁的时候调用
    • 作用:移除观察者,清空数据

举个例子

我们依旧修改以前的代码,给Scott这个Component添加上这些方法,最后代码是这样:

class Scott extends Component {

    // 构造
    constructor(props) {
        super(props);

        console.log("constructor")
    }

    componentWillMount() {
        console.log("componentWillMount")
    }

    componentDidMount() {
        console.log("componentDidMount")
    }

    shouldComponentUpdate() {
        console.log("shouldComponentUpdate")
        return true
    }

    componentWillReceiveProps() {
        console.log("componentWillReceiveProps")
    }

    componentWillUpdate(){
        console.log("componentWillUpdate")
    }

    componentDidUpdate() {
        console.log("componentDidUpdate")
    }

    componentWillUnmount() {
        console.log("componentWillUnmount")
    }

    render() {
        console.log("render")
        return (
            <Text style={styles.welcome}>
                点击注意看Lucy是否变成Scott:
                {this.props.name}
            </Text>
        );
    }
}

export default class Hello extends Component {

    // 构造
    constructor(props) {
        super(props);

        // 初始状态
        this.state = {firstName:"Lucy", lastName:"Tom"};
        this._onPressText = this._onPressText.bind(this);
    }

    _onPressText(){
        this.setState({firstName:"Scott"})
    }

    render() {
        return (
            <View style={styles.container}>
                <TouchableOpacity onPress={this._onPressText}>
                    <Scott name={this.state.firstName + this.state.lastName}/>
                </TouchableOpacity>
            </View>
        );
    }
}

保存代码,选择模拟器,command + R刷新一下界面,然后到Xcode控制台看输出结果,应该是如下图:

我们点击屏幕,触发一下更新,然后可以看到控制台输出结果:

tips: xcode控制台会每隔一秒输出__nw_connection_get_connected_socket_block_invoke 2 Connection has no connected handler, 解决办法:edit scheme -> Run -> Arguments -> Environment Variables -> Add -> Name: "OS_ACTIVITY_MODE"Value:"disable"

致谢

如果发现有错误的地方,欢迎各位指出,谢谢!

时间: 2024-12-28 21:21:28

React Native 系列(二)的相关文章

【REACT NATIVE 系列教程之二】创建自定义组件&&导入与使用示例

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2219.html 在上一篇  [REACT NATIVE 系列教程之一]触摸事件的两种形式与四种TOUCHABLE组件详解 中的最后介绍了如何使用Touchable的四种组件进行监听触摸事件.  那么紧接着我们利用Touchable来包装一个带图片的Button组件,且设计成可接受很多自定义参数. 一:创建我们自定义

【REACT NATIVE 系列教程之十二】REACT NATIVE(JS/ES)与IOS(OBJECT-C)交互通信

一用到跨平台的引擎必然要有引擎与各平台原生进行交互通信的需要.那么Himi先讲解React Native与iOS之间的通信交互. 本篇主要分为两部分讲解:(关于其中讲解的OC语法等不介绍,不懂的请自行学习) 1. React Native 访问iOS 2. iOS访问React Native     一:React Native 访问iOS 1. 我们想要JS调用OC函数,就要实现一个"RCTBridgeModule"协议的Objective-C类 所以首先我们先创建一个oc新类,  

【REACT NATIVE 系列教程之十三】利用LISTVIEW与TEXTINPUT制作聊天/对话框&&获取组件实例常用的两种方式

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2346.html 本篇Himi来利用ListView和TextInput这两种组件实现对话.聊天框. 首先需要准备的有几点:(组件的学习就不赘述了,简单且官方有文档) 1. 学习下 ListView: 官方示例:http://reactnative.cn/docs/0.27/tutorial.html#content

【REACT NATIVE 系列教程之七】统一ANDROID与IOS两个平台的程序入口&&区分平台的组件简介

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2260.html       本篇介绍两个细节:       1. 关于如何将index.android.js 与index.ios.js统一管理起来.       2.  Platform 组件的简单介绍与使用   一:将index.android.js 与index.ios.js统一管理起来. 由于React本身

菜鸟窝React Native 系列教程-1.移动端开发趋势与未来

菜鸟窝React Native 系列教程-1.移动端开发趋势与未来 课程持续更新中..... 我是RichardCao,现任新美大酒店旅游事业群的Android Developer.如果你也有兴趣录制RN视频,请加入下面QQ群找我. 下载地址:https://pan.baidu.com/s/1c1XmE56 密码:shhw 首发地址:菜鸟窝-ReactNative学习板块 交流QQ群:576089067 课程目录:菜鸟窝React Native 系列教程

【REACT NATIVE 系列教程之十一】插件的安装、使用与更新(示例:REACT-NATIVE-TAB-NAVIGATOR)

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2294.html 本篇主要来详细介绍如何安装.升级插件及讲解一个react-native-tab-navigator的示例. 首先推荐一个插件网站:https://www.npmjs.com     (此插件属于半官方维护的) 本文举例使用的插件:react-native-tab-navigator ,选项卡形式的导

【REACT NATIVE 系列教程之一】触摸事件的两种形式与四种TOUCHABLE组件详解

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/react-native/2203.html 本文是RN(React Native)系列教程第一篇,当然也要给自己的群做个广告:   React Native @Himi :126100395  刚创建的群,欢迎一起学习.讨论.进步. 本文主要讲解两点: 1.   PanResponder:触摸事件,用以获取用户手指所在屏幕的坐标(x,y)或触

React Native 系列(七)

前言 本系列是基于React Native版本号0.44.3写的.几乎所有的App都使用了ListView这种组件,这篇文章将学习RN中ListView的平铺样式和分组样式. ListView平铺样式 ListView内部是通过ListViewDataSource这个对象显示数据的,因此使用ListView的时候需要创建一个ListViewDataSource对象. ListViewDataSource构造方法创建对象的时候可以选择性出入4个参数,描述怎么提取cell,怎么刷新cell 这些参数

React Native 系列(九)

前言 本系列是基于React Native版本号0.44.3写的.很多的App都使用了Tab标签组件,例如QQ,微信等等,就是切换不同的选项,显示不同的内容.那么这篇文章将介绍RN中的Tab标签组件. Tab标签 什么是Tab标签?(ps:我是这样叫的),就拿微信来说吧,底部有4个选项卡,点击不同的按钮切换不同的内容.在RN中有两个组件负责实现这样的效果,它们是: TabBarIOS TabNavigator TabBarIOS 和NavigatorIOS相似,看名字就知道该组件只适用于iOS,