React-Native如何调用NodeJs实现的服务器端接口 ------ NodeJs + Express + MySQL 实现的Restful API风格的数据访问接口

react-native 实现的移动客户端支持 安卓和苹果手机

NodeJs + Express + MySQL 实现的Restful API后端数据服务接口

需要的组件全部安装完毕后,我们可以看看package.json文件的内容,尤其是版本信息

{
"name": "zigoo",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"body-parser": "^1.18.2",
"express": "^4.16.3",
"mysqli": "^2.2.2",
"react": "^16.3.0-alpha.1",
"react-native": "0.54.3"
},
"devDependencies": {
"babel-jest": "22.4.3",
"babel-preset-react-native": "4.0.0",
"jest": "22.4.3",
"react-test-renderer": "^16.3.0-alpha.1"
},
"jest": {
"preset": "react-native"
}
}

项目文件的层次结构


将MySQL启动服务的目录配置成全局路径:

myths-Mac:~ myth$ pwd
/Users/myth

myths-Mac:~ myth$ echo 'export PATH=$PATH:/usr/local/mysql/bin' >> ~/.bash_profile

你忘记了MySQL数据库的root密码

首先在Mac OS系统中关掉MySQL服务程序 步骤是:System Preferences ---> MySQL ---> Stop MySQL Server

myths-Mac:~ myth$ sudo su

Password: 123 登录 Mac OS系统的密码

你必须要修改数据库的编码 默认是拉丁文编码 我们需要的是utf-8编码,不这个干 你的中文数据肯定存储的是乱码:

sh-3.2# cat > /etc/my.cnf

# Example MySQL config file for small systems.
#
# This is for a system with little memory (<= 64M) where MySQL is only used
# from time to time and it's important that the mysqld daemon
# doesn't use much resources.
#
# MySQL programs look for option files in a set of
# locations which depend on the deployment platform.
# You can copy this option file to one of those
# locations. For information about these locations,see:
# http://dev.mysql.com/doc/mysql/en/option-files.html
#
# In this file,you can use all long options that a program supports.
# If you want to know which options a program supports,run the program
# with the "--help" option.

# The following options will be passed to all MySQL clients
[client]
default-character-set=utf8
#password = your_password
port = 3306
socket = /tmp/mysql.sock

# Here follows entries for some specific programs

# The MySQL server
[mysqld]
default-storage-engine=INNODB
character-set-server=utf8
collation-server=utf8_general_ci
port = 3306
socket = /tmp/mysql.sock
skip-external-locking
key_buffer_size = 16K
max_allowed_packet = 1M
table_open_cache = 4
sort_buffer_size = 64K
read_buffer_size = 256K
read_rnd_buffer_size = 256K
net_buffer_length = 2K
thread_stack = 128K

# Don't listen on a TCP/IP port at all. This can be a security enhancement,
# if all processes that need to connect to mysqld run on the same host.
# All interaction with mysqld must be made via Unix sockets or named pipes.
# Note that using this option without enabling named pipes on Windows
# (using the "enable-named-pipe" option) will render mysqld useless!
#
#skip-networking
server-id = 1

# Uncomment the following if you want to log updates
#log-bin=mysql-bin

# binary logging format - mixed recommended
#binlog_format=mixed

# Causes updates to non-transactional engines using statement format to be
# written directly to binary log. Before using this option make sure that
# there are no dependencies between transactional and non-transactional
# tables such as in the statement INSERT INTO t_myisam SELECT * FROM
# t_innodb; otherwise,slaves may diverge from the master.
#binlog_direct_non_transactional_updates=TRUE

# Uncomment the following if you are using InnoDB tables
#innodb_data_home_dir = /usr/local/mysql/data
#innodb_data_file_path = ibdata1:10M:autoextend
#innodb_log_group_home_dir = /usr/local/mysql/data
# You can set .._buffer_pool_size up to 50 - 80 %
# of RAM but beware of setting memory usage too high
#innodb_buffer_pool_size = 16M
#innodb_additional_mem_pool_size = 2M
# Set .._log_file_size to 25 % of buffer pool size
#innodb_log_file_size = 5M
#innodb_log_buffer_size = 8M
#innodb_flush_log_at_trx_commit = 1
#innodb_lock_wait_timeout = 50

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
#safe-updates

[myisamchk]
key_buffer_size = 8M
sort_buffer_size = 8M

[mysqlhotcopy]
interactive-timeout


开始跳过输入密码这步进入MySQL服务器:

sh-3.2# mysqld_safe --skip-grant-tables --skip-networking &

sh-3.2# mysql -uroot

mysql> use mysql

mysql> UPDATE user SET authentication_string=PASSWORD('!8@e21#tw') WHERE user='root';

mysql> quit

myths-Mac:~ myth$ mysql -uroot -p

回车输入密码 !8@e21#tw

mysql> use mysql --切换数据库失败不要慌张 它强行让你修改上面刚刚设置的密码 你改成裸奔的 123456 作为密码都不成问题

ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.

mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';

Query OK,0 rows affected (0.00 sec)

你想允许任一IP地址都可以远程去连接你的MySQL数据库服务器,不明白?其中有这样一种情况,你用自己实际的网卡IP去连接数据库是连不上的,我们可以接着执行一条如下的SQL语句即可,其中百分号表示任一IP地址均可访问本数据库服务器,像建立数据库同步账户,就需要这么干:

mysql> GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY '123456';

mysql>FLUSH PRIVILEGES;


开始真正步入正题啦 :

创建数据库 mysql> CREATE DATABASE testdb;

创建users数据表:

mysql> CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`email` varchar(30) DEFAULT NULL,
`mobile` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创始化2条记录:
mysql> insert into users(`id`,`name`,`email`,`mobile`) values(1,'Jack','jack@gmail.com','13570845544');

mysql> insert into users(`id`,`mobile`) values(2,'Jason','jason@sina.com','1380013800');

mysql> quit

我的苹果系统网卡地址是:192.168.123.47

myths-Mac:~ myth$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
en0: flags=8863<UP,BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500
options=b<RXCSUM,VLAN_HWTAGGING>
ether 00:0c:29:60:24:04
inet6 fe80::e0:bbf8:cc2c:3177%en0 prefixlen 64 secured scopeid 0x4
inet 192.168.123.47 netmask 0xffffff00 broadcast 192.168.123.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect (1000baseT <full-duplex>)
status: active
utun0: flags=8051<UP,POINTOPOINT,MULTICAST> mtu 2000
inet6 fe80::6ea7:d379:ecc3:e2a6%utun0 prefixlen 64 scopeid 0x5
nd6 options=201<PERFORMNUD,DAD>

myths-Mac:~ myth$

我们可以用SQLyog 这样的可视化客户端工具去操作苹果系统中的MySQL服务器了,没这个工具自己在网上随便下载一个

开始使用命令建立一个 react-native 项目:

myths-Mac:~ myth$ react-native init zigoo

myths-Mac:~ myth$ pwd
/Users/myth

myths-Mac:~ myth$ cd zigoo

myths-Mac:~ myth$ yarn add express

myths-Mac:~ myth$ yarn add mysqli

myths-Mac:~ myth$ yarn add body-parser

使用Android Studio 或者其它你喜欢的开发工具在App.js同一目录中建立一个空的server.js代码文件,你可以用命令查看一下:

myths-Mac:zigoo myth$ ls
App.js app.json ios server.js
__tests__ gen node_modules yarn.lock
android index.js package.json

myths-Mac:zigoo myth$ cat server.js

var express = require('express');
var app = express();
var mysql = require('mysql');
var bodyParser = require('body-parser');
app.use(bodyParser.json({type: 'application/json'}));
app.use(bodyParser.urlencoded({extended: true}));

var conn = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '123456',
database: 'testdb'
});

var server = app.listen(9090,function(){
var host = server.address().address
var port = server.address().port
console.log('server start')
});

conn.connect(function(error){
if(!!error) console.log('error');
else console.log('connected');
});

app.get('/users',function(req,res){
conn.query('SELECT * FROM users',function(error,rows,fields){
if(!!error) console.log('error');
else {
console.log(rows);
res.send(rows);
}
})
});

app.post('/users',res){
conn.query('INSERT INTO users SET ?',req.body,fields){
if(!!error) console.log('error');
else {
console.log(req.body)
console.log(rows);
res.send(JSON.stringify(rows));
}
})
})

app.get('/users/:id',res){
conn.query('SELECT * FROM users WHERE id=?',req.params.id,fields){
if(!!error) console.log('error');
else {
console.log(rows);
res.send(JSON.stringify(rows));
}
})
});

app.delete('/users/:id',res){
conn.query('DELETE FROM users WHERE id=?',fields){
if(!!error) console.log('error');
else {
console.log(rows);
res.end('deleted successfully');
}
})
});

app.put('/users',res){
conn.query('UPDATE users SET name=?,email=?,mobile=? WHERE id=?',
[req.body.name,req.body.email,req.body.mobile,req.body.id],fields){
if(!!error) console.log('error');
else {
console.log(req.body)
console.log(rows);
res.send(JSON.stringify(rows));
}
})
})

/*
启动方式
myths-Mac:zigoo myth$ node ./server.js

访问数据接口
http://localhost:9090/users

[{"id":1,"name":"Jack","emial":"jack@gmail.com","mobile":"13570845544"},{"id":2,"name":"Jason","emial":"jason@sina.com","mobile":"1380013800"}]
*/

现在介绍如何用Postman工具来测试上面Restful API 数据操作接口

使用如下命令启动 (MySQL + NodeJs + Express)实现的服务器端服务程序:

$cd /Users/myth/zigoo && node ./server.js


Restful API 测试工具Postman

(一). 获取所有用户的记录

Method

GET http://192.168.123.47:9090/users

Output Raw
[{"id":1,"email":"jack@gmail.com",

{"id":2,"email":"jason@sina.com","mobile":"13800138000"}]

(二). 新增一个用户

Method

POST http://192.168.123.47:9090/users

Headers
Accept application/json
Content-Type application/x-www-form-urlencoded

Body x-www-form-urlencoded
key value
name James
email james@126.com
mobile 13800888010

Output Pretty

{"fieldCount":0,"affectedRows":1,"insertId":16,"serverStatus":2,"warningCount":0,"message":"","protocol41":true,"changedRows":0}

查看刚刚新增的1条用户记录:

myths-Mac:~ myth$ mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 516
Server version: 5.7.21 MySQL Community Server (GPL)
Copyright (c) 2000,2018,Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> use testdb
Database changed
mysql> select * from users;
+----+-------+----------------+-------------+
| id | name | email | mobile |
+----+-------+----------------+-------------+
| 1 | Jack | jack@gmail.com | 13570845544 |
| 2 | Jason | jason@sina.com | 13800138000 |
| 3 | James | james@126.com | 13800888010 |
+----+-------+----------------+-------------+
3 rows in set (0.00 sec)
mysql>

(三). 根据主键获取一个用户

Method

GET http://192.168.123.47:9090/users/3

Output Raw

[{"id":3,"name":"James","email":"james@126.com","mobile":"13800888010"}]

(四). 根据主键删除一个用户

Method

DELETE http://192.168.123.47:9090/users/3

Output Raw

deleted successfully

查看刚刚删除的1条记录(主键 id =3)是否真的不存在,显示它已经被删除:

mysql> select * from users;
+----+-------+----------------+-------------+
| id | name | email | mobile |
+----+-------+----------------+-------------+
| 1 | Jack | jack@gmail.com | 13570845544 |
| 2 | Jason | jason@sina.com | 13800138000 |
+----+-------+----------------+-------------+
2 rows in set (0.00 sec)
mysql>

(五). 根据主键(id = 2)还有其它所有字段的值修改一条已经存在的记录:

Method
PUT http://192.168.123.47:9090/users

Headers
Accept application/json
Content-Type application/x-www-form-urlencoded

Body x-www-form-urlencoded
key value
name James
email james@126.com
mobile 13800888010
id 2

Output Pretty

{"fieldCount":0,"insertId":0,"message":"(Rows matched: 1 Changed: 1 Warnings: 0","changedRows":1}

查看刚刚删修改的1条记录(主键 id =2)是否真的已被更改,显示它已经被修改过了:

mysql> select * from users;
+----+-------+----------------+-------------+
| id | name | email | mobile |
+----+-------+----------------+-------------+
| 1 | Jack | jack@gmail.com | 13570845544 |
| 2 | James | james@126.com | 13800888010 |
+----+-------+----------------+-------------+
2 rows in set (0.00 sec)

mysql>

现在接下来实现移动端react-native 代码,只用到了一个App.js文件,代码如下:

import React,{ Component } from 'react';
import {
StyleSheet,
Text,
TextInput,
View,
ScrollView,
TouchableHighlight
} from 'react-native';

export default class App extends Component {
constructor(props){
super(props)
this.state = {
apiData: [],
naData: []
}
this.uid = null;
this.name = null;
this.email = null;
this.mobile = null;
}

onGetUsers = () => {
fetch('http://192.168.123.47:9090/users',{
method: 'GET'
}).then((response) => {
return response.json();
}).then((jsonData) => {
this.setState({
apiData: jsonData,
})
console.log(this.state.apiData);
})
.catch((error) => {
console.warn(error);
}).done();
this.uid = null;
}

onPostUser = () => {
fetch('http://192.168.123.47:9090/users',{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: this.name,email: this.email,mobile: this.mobile })
}).then((response) => {
return response.json();
}).then((jsonData) => {
this.setState({
naData: jsonData,
})
console.log(this.state.naData);
})
.catch((error) => {
console.warn(error);
}).done();
this.uid = null;
this.name = null;
this.email = null;
this.mobile = null;
}

onGetUser = () => {
fetch('http://192.168.123.47:9090/users/'+ this.uid,
})
console.log(this.state.apiData);
})
.catch((error) => {
console.warn(error);
}).done();
this.uid = null;
}

onDeleteUser = () => {
fetch('http://192.168.123.47:9090/users/'+ this.uid,{
method: 'DELETE'
}).then((response) => {
console.log(response.rows);
}).catch((error) => {
console.warn(error);
}).done();
this.uid = null;
}

onPutUser = () => {
fetch('http://192.168.123.47:9090/users',{
method: 'PUT',mobile: this.mobile,id: this.uid })
}).then((response) => {
return response.json();
}).catch((error) => {
console.warn(error);
}).done();
this.uid = null;
this.name = null;
this.email = null;
this.mobile = null;
}

render() {
const data = this.state.apiData;
let dataDisplay = data.map(function(jsonData){
return (
<View key={jsonData.id}>
<View style={{flexDirection: 'row'}}>
<Text style={{color: '#000',width: 30}}>{jsonData.id}</Text>
<Text style={{color: '#00f',width: 60}}>{jsonData.name}</Text>
<Text style={{color: '#000',width: 140}}>{jsonData.email}</Text>
<Text style={{color: '#00f',width: 100}}>{jsonData.mobile}</Text>
</View>
</View>
)
});

return (
<View style={styles.container}>
<Text style={{fontSize: 20,textAlign: 'center',marginTop: 10}}>
My App Users
</Text>
<View style={{height: 2,backgroundColor: '#ccc',marginBottom: 10,width: '90%'}}></View>
<TextInput style={styles.input}
placeholder = 'id'
onChangeText ={(text) => {this.uid = text}}
value = {this.id}
underlineColorAndroid = 'transparent'
/>
<TextInput style={styles.input}
placeholder = 'name'
onChangeText ={(text) => {this.name = text}}
value = {this.name}
underlineColorAndroid = 'transparent'
/>
<TextInput style={styles.input}
placeholder = 'email'
onChangeText ={(text) => {this.email = text}}
value = {this.email}
underlineColorAndroid = 'transparent'
/>
<TextInput style={styles.input}
placeholder = 'mobile'
onChangeText ={(text) => {this.mobile = text}}
value = {this.mobile}
underlineColorAndroid = 'transparent'
/>
<TouchableHighlight style={styles.button} onPress={this.onGetUsers}>
<Text style={styles.buttonText}>GET All Users</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} onPress={this.onPostUser}>
<Text style={styles.buttonText}>POST a User</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} onPress={this.onGetUser}>
<Text style={styles.buttonText}>GET a User</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} onPress={this.onDeleteUser}>
<Text style={styles.buttonText}>DELETE a User</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} onPress={this.onPutUser}>
<Text style={styles.buttonText}>PUT a User</Text>
</TouchableHighlight>
<ScrollView contentContainerStyle={styles.container}>
{dataDisplay}
</ScrollView>
</View>
);
}
}

const styles = StyleSheet.create({
container: {
marginTop: 5,
flex: 1,
alignItems: 'center',
backgroundColor: '#fff',
},
input: {
textAlign: 'left',
height: 30,
width: '90%',
padding: 4,
marginBottom: 7,
fontSize: 16,
fontWeight:'500',
borderWidth: 1,
button: {
paddingTop: 10,
paddingBottom: 10,
borderRadius: 25,
marginTop: 3,
marginBottom: 3,
backgroundColor: '#00bcd4'
},
buttonText: {
color: '#fff',
textAlign: 'center',
fontSize:16,
}

});

最后来看看iOS&Android模拟器中运行的效果截图吧



版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom