1, 环境搭建
环境搭建中文教程, 点击跳转 RN 中文社区 :
社区内容讲得很详细, 大家跟着操作一步一步来即可, 遇到问题, 直接百度. 也可以看看这篇文章: React Native 填坑指南 https://www.jianshu.com/p/276cb2c0283a 会教你如何把坑填平.
2,React Native 基础
先来看看一个实例, 这个地址源码地址: 示例教程: 电影列表. 之所以选择这个例子, 是因为它包含了几乎所有的 react native 入门基础知识.
- import React, { Component } from "react";
- import { Image, FlatList, StyleSheet, Text, View } from "react-native";
- var REQUEST_URL =
- "https://raw.githubusercontent.com/Facebook/react-native/0.51-stable/docs/MoviesExample.JSON";
- export default class SampleAppMovies extends Component {
- constructor(props) {
- super(props);
- this.state = {
- data: [],
- loaded: false
- };
- // 在 ES6 中, 如果在自定义的函数里使用了 this 关键字, 则需要对其进行 "绑定" 操作, 否则 this 的指向会变为空
- // 像下面这行代码一样, 在 constructor 中使用 bind 是其中一种做法(还有一些其他做法, 如使用箭头函数等)
- this.fetchData = this.fetchData.bind(this);
- }
- componentDidMount() {
- this.fetchData();
- }
- fetchData() {
- fetch(REQUEST_URL)
- .then(response => response.JSON())
- .then(responseData => {
- // 注意, 这里使用了 this 关键字, 为了保证 this 在调用时仍然指向当前组件, 我们需要对其进行 "绑定" 操作
- this.setState({
- data: this.state.data.concat(responseData.movies),
- loaded: true
- });
- });
- }
- render() {
- if (!this.state.loaded) {
- return this.renderLoadingView();
- }
- return (
- <FlatList
- data={this.state.data}
- renderItem={this.renderMovie}
- style={styles.list}
- />
- );
- }
- renderLoadingView() {
- return (
- <View style={styles.container}>
- <Text>Loading movies...</Text>
- </View>
- );
- }
- renderMovie({ item }) {
- // { item }是一种 "解构" 写法, 请阅读 ES2015 语法的相关文档
- // item 也是 FlatList 中固定的参数名, 请阅读 FlatList 的相关文档
- return (
- <View style={styles.container}>
- <Image
- source={{ uri: item.posters.thumbnail }}
- style={styles.thumbnail}
- />
- <View style={styles.rightContainer}>
- <Text style={styles.title}>{item.title}</Text>
- <Text style={styles.year}>{item.year}</Text>
- </View>
- </View>
- );
- }
- }
- var styles = StyleSheet.create({
- container: {
- flex: 1,
- flexDirection: "row",
- justifyContent: "center",
- alignItems: "center",
- backgroundColor: "#F5FCFF"
- },
- rightContainer: {
- flex: 1
- },
- title: {
- fontSize: 20,
- marginBottom: 8,
- textAlign: "center"
- },
- year: {
- textAlign: "center"
- },
- thumbnail: {
- width: 53,
- height: 81
- },
- list: {
- paddingTop: 20,
- backgroundColor: "#F5FCFF"
- }
- });
这个例子从电影数据库中取得最近正在上映的 25 部电影, 并在一个 FlatList 中展示出来.
- 2.1 import
- import React,{
- Component
- } from 'react';
- // 导入'react'文件里 export 的一个默认的组件, 将其命名为 React 以及 Component 这个非默认组件
还有其他一些 import 的用法, 具体含义如下:
import defaultcomponent form 'XXX' 导入 XXX 文件中的默认组件, 命名为 defaultcomponent
import {a} from 'XXX' 导入 XXX 文件中的 a 组件
import {a as b} from 'XXX' 导入 XXX 文件中的 a 组件, 并将其重命名为 b
import * as a from 'XXX' 导入 XXX 文件中的所有组件, 并将其命名为 a, 调用具体组件的方式为 a.b,a.c... 但不包含默认组件
2.2 var 定义变量
在组件前面, 定一个变量 REQUEST_URL 用于保存请求网址,.
2.3 export 语句
模块的功能有两个关键字: export 和 import.export 用于用户自定义模块. import 用于输入其他模块的功能, 同时创建命名空间(namespace), 防止函数名冲突.
ES6 允许将独立的 JS 文件作为模块, 也就是说, 允许一个 JavaScript 脚本文件调用另一个脚本文件. 最简单的模块就是一个 JS 文件, 里面使用 export 关键字输出变量.
- //profile.JS
- export var firstName = "Pandora";
- export var lastName = "G.Dragon";
- export var year = 1973;
- //export 还有下面这种写法, 两者是等价的
- var firstName = "Pandora";
- var lastName = "G.Dragon";
- var year = 1973;
- export({firstName, lastName, year});
使用 export 定义模块之后, 其他 JS 文件就可以通过 import 关键字加载这个模块 (文件) 了. 加载方式如下:
- import {firstName, lastName, year} from './profile';
- function setHeader(element) {
- element.textContent = firstName + '' + lastName;
- }
上面的代码片段中, 使用了 import 关键字接受一个对象 -- 用 "{ }" 表示. 里面指定了要从其他模块中导入的变量. 大括号里面的变量名必须与被导入模块对外接口的名称相同.
2.4 Class 类
ES6 提供了更接近传统语言的写法, 引入了 Class(类)这个概念, 作为对象的模板. 通过 class 关键字, 可以定义类. 基本上, ES6 的 class 可以看作只是一个语法糖, 它的绝大部分功能, ES5 都可以做到, 新的 class 写法只是让对象原型的写法更加清晰, 更像面向对象编程的语法而已. 上面的代码用 ES6 的 "类" 改写, 就是下面这样.
- // 定义类
- class Point {
- constructor(x, y) {
- this.x = x;
- this.y = y;
- }
- toString() {
- return '(' + this.x + ',' + this.y + ')';
- }
- }
上面代码定义了一个 "类", 可以看到里面有一个 constructor 方法, 这就是构造方法, 而 this 关键字则代表实例对象. 也就是说, ES5 的构造函数 Point, 对应 ES6 的 Point 类的构造方法.
Point 类除了构造方法, 还定义了一个 toString 方法. 注意, 定义 "类" 的方法的时候, 前面不需要加上 function 这个关键字, 直接把函数定义放进去了就可以了. 另外, 方法之间不需要逗号分隔, 加了会报错.
Class 之间可以通过 extends 关键字实现继承, 这比 ES5 的通过修改原型链实现继承, 要清晰和方便很多.
class ColorPoint extends Point {}
上面代码定义了一个 ColorPoint 类, 该类通过 extends 关键字, 继承了 Point 类的所有属性和方法. 但是由于没有部署任何代码, 所以这两个类完全一样, 等于复制了一个 Point 类. 下面, 我们在 ColorPoint 内部加上代码.
- class ColorPoint extends Point {
- constructor(x, y, color) {
- super(x, y); // 调用父类的 constructor(x, y)
- this.color = color;
- }
- toString() {
- return this.color + ' ' + super.toString(); // 调用父类的 toString()
- }
- }
上面代码中, constructor 方法和 toString 方法之中, 都出现了 super 关键字, 它在这里表示父类的构造函数, 用来新建父类的 this 对象.
子类必须在 constructor 方法中调用 super 方法, 否则新建实例时会报错. 这是因为子类没有自己的 this 对象, 而是继承父类的 this 对象, 然后对其进行加工. 如果不调用 super 方法, 子类就得不到 this 对象.
2.5 Props(属性)
大多数组件在创建时就可以使用各种参数来进行定制. 用于定制的这些参数就称为 props(属性).
以常见的基础组件 Image 为例, 在创建一个图片时, 可以传入一个名为 source 的 prop 来指定要显示的图片的地址, 以及使用名为 style 的 prop 来控制其尺寸.
- 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}} />
- );
- }
- }
- 2.6 state
props 是在父组件中指定, 而且一经指定, 在被指定的组件的生命周期中则不再改变. 对于需要改变的数据, 我们需要使用 state.
大多数组件在创建时就可以使用各种参数来进行定制. 用于定制的这些参数就称为 props(属性).
一般来说, 你需要在 constructor 中初始化 state(译注: 这是 ES6 的写法, 早期的很多 ES5 的例子使用的是 getInitialState 方法来初始化 state, 这一做法会逐渐被淘汰), 然后在需要修改时调用 setState 方法.
提示一些初学者应该牢记的要点:
一切界面变化都是状态 state 变化
state 的修改必须通过 setState()方法
this.state.likes = 100; // 这样的直接赋值修改无效!
setState 是一个 merge 合并操作, 只修改指定属性, 不影响其他属性
setState 是异步操作, 修改不会马上生效
2.7 react native 生命周期
组件的生命周期方法对应着组件的不同生命阶段, 通常我们分为三个阶段: 组件初始化及挂载阶段, 组件运行期阶段及组件卸载阶段.
初始化及挂载阶段
一, 这是组件类的构造函数, 通常在此初始化 state 数据模型.
- constructor(props) {
- super(props);
- this.state = {
- //key : value
- };
- }
二, 表示组件将要加载到虚拟 DOM, 在 render 方法之前执行, 整个生命周期只执行一次.
- componentWillMount() {
- }
三, 表示组件已经加载到虚拟 DOM, 在 render 方法之后执行, 整个生命周期只执行一次. 通常在该方法中完成异步网络请求或者集成其他 JavaScript 库.
- componentDidMount() {
- }
运行期阶段
一, 在组件接收到其父组件传递的 props 的时候执行, 参数为父组件传递的 props. 在组件的整个生命周期可以多次执行. 通常在此方法接收新的 props 值, 重新设置 state.
- componentWillReceiveProps(nextProps) {
- this.setState({
- //key : value
- });
- }
二, 在 componentWillReceiveProps(nextProps)执行之后立刻执行; 或者在 state 更改之后立刻执行. 该方法包含两个参数, 分别是 props 和 state. 该方法在组件的整个生命周期可以多次执行. 如果该方法返回 false, 则 componentWillUpdate(nextProps, nextState)及其之后执行的方法都不会执行, 组件则不会进行重新渲染.
- shouldComponentUpdate(nextProps, nextState) {
- return true;
- }
二, 在 shouldComponentUpdate(nextProps, nextState)函数执行完毕之后立刻调用, 该方法包含两个参数, 分别是 props 和 state.render() 函数执行之前调用. 该方法在组件的整个生命周期可以多次执行.
- componentWillUpdate(nextProps, nextState) {
- }
三, 在 render() 方法执行之后立刻调用. 该方法包含两个参数, 分别是 props 和 state. 该方法在组件的整个生命周期可以多次执行.
- componentDidUpdate(preProps, preState) {
- }
四, render 方法用于渲染组件. 在初始化阶段和运行期阶段都会执行.
- render() {
- return(
- <View/>
- );
- }
卸载阶段
一, 在组件由虚拟 DOM 卸载的时候调用.
- componentWillUnmount() {
- }
- 2.8 fetch
fetch, 说白了, 就是 XMLHttpRequest 的一种替代方案. 如果有人问你, 除了 Ajax 获取后台数据之外, 还有没有其他的替代方案? 答案是还可以使用一种更优的解决方案 fetch.
到现在为止, fetch 的支持性还不是很好, 但是在谷歌浏览器中已经支持了 fetch.fetch 挂在在 BOM 中, 可以直接在谷歌浏览器中使用.
查看 fetch 的支持情况: fetch 的支持情况
fetch 方法会返回一个 , 这种模式可以简化异步风格的代码. 如果你想了解 promise 的含义, 可以参考文章 : 手把手教你实现一个完整的 Promise . 带你了解 promise 的本质内核.
下面我们来写第一个 fetch 获取后端数据的例子:
- // 通过 fetch 获取百度的错误提示页面
- fetch('https://www.baidu.com/search/error.html') // 返回一个 Promise 对象
- .then((res)=>{
- return res.text() // res.text()是一个 Promise 对象
- })
- .then((res)=>{
- console.log(res) // res 是最终的结果
- })
是不是很简单? 再来看看 get 和 post 方法的使用:
- // 通过 fetch 获取百度的错误提示页面
- fetch('https://www.baidu.com/search/error.HTML?a=1&b=2', { // 在 URL 中写上传递的参数
- method: 'GET'
- })
- /* post 方法, 把前面的 get 注释即可
- fetch('https://www.baidu.com/search/error.HTML', {
- method: 'POST',
- body: new URLSearchParams([["foo", 1],["bar", 2]]).toString() // 这里是请求对象
- })
- */
- .then((res)=>{
- return res.text()
- })
- .then((res)=>{
- console.log(res)
- })
React Native 中已经内置了 XMLHttpRequest API (也就是俗称的 Ajax). 一些基于 XMLHttpRequest 封装的第三方库也可以使用, 例如 https://GitHub.com/niftylettuce/frisbee 或是 https://GitHub.com/mzabriskie/axios 等. 但注意不能使用 jQuery, 因为 jQuery 中还使用了很多浏览器中才有而 RN 中没有的东西(所以也不是所有 web 中的 Ajax 库都可以直接使用).
2.9 样式
style 的定义方式:
1, 直接在 render()函数中定义
- //todo 设置样式一, 直接在 render 中定义样式
- var mStyle = {
- color:'red',fontSize:34
- };
- return<Text style={
- mStyle
- }> https://GitHub.com/93Laer </Text>
- // or 类似于安卓中的匿名内部内
- // return<Text style={
- {
- color:'red',fontSize:34
- }
- }> https://GitHub.com/93Laer </Text>
2, 方式二, 通过 StyleSheet 创建 style, 测试多个 style, 以哪个为准
- // 创建样式
- const styles = StyleSheet.create({
- bigblue:{
- color:'blue',
- fontSize:34,
- fontWeight:'bold'
- },
- red:{
- color:'red',
- fontSize:14
- }
- });
- // 使用样式
- //todo 设置样式二, 通过 StyleSheet 创建样式
- return<Text style={styles.bigblue}> https ://GitHub.com/93Laer </Text>
直接在组件中传入多个 style 对象, 最后显示的效果就不展示了, 在结尾直接给出结论
- // 这里通过多种方式定义 style, 主要是告诉读者定义 style 的多种方式
- var mStyle = {color:'red',fontSize:34};
- return<Text style={[mStyle,{color: 'blue',fontSize:20}]}> https ://GitHub.com/93Laer </Text>
通过 StyleSheet 创建多个 style, 并传入
return<Text style={[styles.bigblue,styles.red]}> https ://GitHub.com/93Laer </Text>
结论: 当设置多个 style 时以最后一个为准, 可理解为最后一个将之前的样式覆盖了. 也可理解为, style 从 styles 数组中依次拿出 style, 并赋值给自己, 所以最后一次赋值就会显示效果
到此, 关于 react native 入门的基础知识就讲解完毕了.
来源: https://www.cnblogs.com/huansky/p/9697178.html