目录
1. 搭建开发环境
2. HelloWorld
3. 组件的属性、状态、样式、宽高、布局
4. 网络
概念
由Facebook发布于2015年
优势
1、跨平台,减少开发成本。
2、即时更新。直接将js上传给后台即可完成更新。
3、利用 JSCore 转化成 Native ,相比基于Webview的其他跨平台性能高很多
运行机制
在启动React Native应用后,会从服务器下载最新的 JS Bundle 文件,然后JavascriptCore 引擎对 JS 文件进行解析,并利用 Bridge 映射到对应的 Native 方法和 UI 控件。
- 搭建开发环境
环境依赖:node、watchman 、React Native 命令行工具、 Xcode
<1> 使用brew安装node、watchman(需先安装brew)
brew install node
brew install watchman
说明:
1、watchman是由 Facebook 提供的监视文件系统变更的工具。安装此工具可以提高开发时的性能(packager 可以快速捕捉文件的变化从而实现实时刷新)。
<2>安装yarn、react-native-cli
设置镜像源
npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global
安装yarn、react-native-cli
npm install -g yarn react-native-cli
设置镜像源
yarn config set registry https://registry.npm.taobao.org --global
yarn config set disturl https://npm.taobao.org/dist --global
说明:
1、yarn是 Facebook 提供的替代 npm 的工具,可以加速 node 模块的下载。
2、React Native 的命令行工具用于执行创建、初始化、更新、运行、打包项目等任务。
<3>创建应用
react-native init AwesomeProject
或
react-native init AwesomeProject --version 0.44.3
![](https://img.haomeiwen.com/i5111884/dc05940eb50e6aa0.png)
android、ios文件夹
存放各自平台的工程项目
node_modules文件夹
存放自动生成的node 依赖之类的文件(通过读取 package.json 里的配置来生成)
<4>运行应用
cd AwesomeProject
react-native run-ios
react-native run-ios --configuration Release
react-native run-ios --simulator "iPhone 4s"
react-native run-android
![](https://img.haomeiwen.com/i5111884/44ced08d347a45fa.png)
查询可用的设备名称
xcrun simctl list devices
<5>牛刀小试:修改App.js文件的显示文本,iOS使用模拟器cmd+R进行刷新界面,Android模拟器按F2
import React, { Component } from 'react';
import { Text, View } from 'react-native';
export default class HelloWorldApp extends Component {
render() {
return (
<View>
<Text>Hello world!</Text>
</View>
);
}
}
自定义了一个HelloWorldApp组件,并显示
- HelloWorld
使用模拟数据
import React, { Component } from "react";
import { Image, StyleSheet, Text, View } from "react-native";
var MOCKED_MOVIES_DATA = [
{
title: "Hello World!",
year: "2019",
posters: { thumbnail: "http://i.imgur.com/UePbdph.jpg" }
}
];
export default class FetchExample extends React.Component {
render() {
var movie = MOCKED_MOVIES_DATA[0];
return (
<View style={styles.container}>
<Image source={{ uri: movie.posters.thumbnail }} style={styles.thumbnail} />
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
rightContainer: {
flex: 1, /*占据 Image 之外剩下的全部空间*/
},
title: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
year: {
textAlign: 'center',
},
thumbnail: {
width: 53,
height: 81
}
});
使用网络数据
import React, { Component } from "react";
import { Image, 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 FetchExample extends React.Component {
constructor(props) {
super(props); // 这一句不能省略
this.state = {
movies: null, // 自定义的state变量及初始值
};
// 在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({
movies: responseData.movies,
});
});
}
render() {
if (!this.state.movies) {
return this.renderLoadingView();
}
var movie = this.state.movies[0];
return this.renderMovie(movie);
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>
正在加载电影数据……
</Text>
</View>
);
}
renderMovie(movie) {
return (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
rightContainer: {
flex: 1, /*占据 Image 之外剩下的全部空间*/
},
title: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
year: {
textAlign: 'center',
},
thumbnail: {
width: 53,
height: 81
}
});
列表FlatList
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"
}
});
- 组件的属性、状态、样式、宽高、布局
···组件的属性···
实例1
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}说明:
括号内部为一个 js 变量或表达式,需要执行后取值。因此我们可以把任意合法的 JavaScript 表达式通过括号嵌入到 JSX 语句中。
实例2
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'}}>
<Greeting name='Rexxar' />
<Greeting name='Jaina' />
<Greeting name='Valeera' />
</View>
);
}
}
属性说明:
自定义组件内部可以使用{this.props.属性},来访问创建组件时添加的属性。
值不再改变。
···组件的状态···
实例1
import React, { Component } from 'react';
import { Text, View } from 'react-native';
class Blink extends Component {
constructor(props) {
super(props);
this.state = { isShowingText: true };
// 每1000毫秒对showText状态做一次取反操作
setInterval(() => {
this.setState(previousState => {
return { isShowingText: !previousState.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>
);
}
}
状态说明:
每调用一次setState方法,会重新执行render方法。
state的修改必须通过setState方法,不能直接赋值。
setState方法是异步操作。
···组件的样式···
实例1
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
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>
);
}
}
const styles = StyleSheet.create({
bigblue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
样式说明:
使用style属性。
与js中的命名的区别:使用驼峰命名法。
数组中相同属性 位置靠后则优先级高。
···组件的宽高···
实例1(固定值)
import React, { Component } from 'react';
import { AppRegistry, 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>
);
}
}
说明:
指定固定的width和height
React Native 中的尺寸都是无单位的
实例2(弹性宽高)
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class FlexDimensionsBasics extends Component {
render() {
return (
<View style={{flex: 1}}>
<View style={{flex: 1, backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
</View>
);
}
}
说明:
前提是父控件必须宽高设定(flex或固定宽高)
flex:1 指定某个组件扩张以撑满所有剩余的空间
多个并列的子组件使用了flex:1,则按比例平分
···组件的布局···
实例1
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class FlexDirectionBasics extends Component {
render() {
return (
<View style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'stretch',
}}>
<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>
);
}
};
说明:
flexDirection:column(默认,从上到下)、row(从左到右)。决定主轴排列方向。
alignItems:flex-start、center、flex-end以及stretch。决定次轴的排列方式。
justifyContent:flex-start、center、flex-end、space-around、space-between以及space-evenly。决定子项的排列方式(开始端、中心、结尾端、、中间空白、)
- 网络
请求
fetch("https://mywebsite.com/mydata.json");
fetch("https://mywebsite.com/endpoint/", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
firstParam: "yourValue",
secondParam: "yourOtherValue"
})
});
fetch("https://mywebsite.com/endpoint/", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "key1=value1&key2=value2"
});
提交数据的格式关键取决于 headers 中的Content-Type。Content-Type有很多种,对应 body 的格式也有区别。
完整的请求并获取数据
function getMoviesFromApiAsync() {
return fetch("https://facebook.github.io/react-native/movies.json")
.then(response => response.json())
.then(responseJson => {
return responseJson.movies;
})
.catch(error => {
console.error(error);
});
}
async function getMoviesFromApi() {
try {
// 注意这里的await语句,其所在的函数必须有async关键字声明
let response = await fetch(
"https://facebook.github.io/react-native/movies.json"
);
let responseJson = await response.json();
return responseJson.movies;
} catch (error) {
console.error(error);
}
}
import React from 'react';
import { FlatList, ActivityIndicator, Text, View } from 'react-native';
export default class FetchExample extends React.Component {
constructor(props){
super(props);
this.state ={ isLoading: true}
}
componentDidMount(){
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson.movies,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
render(){
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return(
<View style={{flex: 1, paddingTop:20}}>
<FlatList
data={this.state.dataSource}
renderItem={({item}) => <Text>{item.title}, {item.releaseYear}</Text>}
keyExtractor={(item, index) => item.id}
/>
</View>
);
}
}
XMLHttpRequest(内置)
var request = new XMLHttpRequest();
request.onreadystatechange = e => {
if (request.readyState !== 4) {
return;
}
if (request.status === 200) {
console.log("success", request.responseText);
} else {
console.warn("error");
}
};
request.open("GET", "https://mywebsite.com/endpoint/");
request.send();
WebSocket
var ws = new WebSocket("ws://host.com/path");
ws.onopen = () => {
// connection opened
ws.send("something"); // send a message
};
ws.onmessage = e => {
// a message was received
console.log(e.data);
};
ws.onerror = e => {
// an error occurred
console.log(e.message);
};
ws.onclose = e => {
// connection closed
console.log(e.code, e.reason);
};
网友评论