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


Apache + ThinkPHP 5.1 + MySQL 实现的Restful API风格的数据访问接口

[myth@contoso ~]$ whoami
myth
[myth@contoso ~]$ pwd
/home/myth

单向数字证书
[root@contoso ~]# openssl genrsa -out ca-app.key 2048 ## 1). 生成一个CA私钥
Generating RSA private key,2048 bit long modulus
.......................................................................................................................................................+++
..........+++
e is 65537 (0x10001)
[root@contoso ~]# openssl req -x509 -new -nodes -key ca-app.key -days 365 -out ca-app.crt ## 2).使用ca-app私钥生成客户端的数字证书
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.',the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:GuangDong
Locality Name (eg,city) [Default City]:ShenZhen
Organization Name (eg,company) [Default Company Ltd]:ZiGoo
Organizational Unit Name (eg,section) []: ## 直接按回车键跳过
Common Name (eg,your name or your server's hostname) []:mo.com
Email Address []:zhengzizhi@126.com
[root@contoso ~]# cp ca-app.key /etc/pki/tls/private/
[root@contoso ~]# cp ca-app.crt /etc/pki/tls/certs/
私钥文件 ca-app.key
数字证书 ca-app.crt

你学习PHP很久了,还搞不定Apache在PHP开发时项目的执行和读写访问权限问题

直接在httpd.conf配置文件查看apache执行用户和执行组,在以下红色字体标识的66行和67行即是用户和用户组,我们要把第66行和第67行改成如下的样子,其中myth是我登录CentOS 7.2系统的用户名

66 User myth

67 Group myth

[root@contoso ~]# cat -n /etc/httpd/conf/httpd.conf
1 #
2 # This is the main Apache HTTP server configuration file. It contains the
3 # configuration directives that give the server its instructions.
4 # See <URL:http://httpd.apache.org/docs/2.4/> for detailed information.
5 # In particular,see
6 # <URL:http://httpd.apache.org/docs/2.4/mod/directives.html>
7 # for a discussion of each configuration directive.
8 #
9 # Do NOT simply read the instructions in here without understanding
10 # what they do. They're here only as hints or reminders. If you are unsure
11 # consult the online docs. You have been warned.
12 #
13 # Configuration and logfile names: If the filenames you specify for many
14 # of the server's control files begin with "/" (or "drive:/" for Win32),the
15 # server will use that explicit path. If the filenames do *not* begin
16 # with "/",the value of ServerRoot is prepended -- so 'log/access_log'
17 # with ServerRoot set to '/www' will be interpreted by the
18 # server as '/www/log/access_log',where as '/log/access_log' will be
19 # interpreted as '/log/access_log'.
20
21 #
22 # ServerRoot: The top of the directory tree under which the server's
23 # configuration,error,and log files are kept.
24 #
25 # Do not add a slash at the end of the directory path. If you point
26 # ServerRoot at a non-local disk,be sure to specify a local disk on the
27 # Mutex directive,if file-based mutexes are used. If you wish to share the
28 # same ServerRoot for multiple httpd daemons,you will need to change at
29 # least PidFile.
30 #
31 ServerRoot "/etc/httpd"
32
33 #
34 # Listen: Allows you to bind Apache to specific IP addresses and/or
35 # ports,instead of the default. See also the <VirtualHost>
36 # directive.
37 #
38 # Change this to Listen on specific IP addresses as shown below to
39 # prevent Apache from glomming onto all bound IP addresses.
40 #
41 #Listen 12.34.56.78:80
42 Listen 80
43
44 #
45 # Dynamic Shared Object (DSO) Support
46 #
47 # To be able to use the functionality of a module which was built as a DSO you
48 # have to place corresponding `LoadModule' lines at this location so the
49 # directives contained in it are actually available _before_ they are used.
50 # Statically compiled modules (those listed by `httpd -l') do not need
51 # to be loaded here.
52 #
53 # Example:
54 # LoadModule foo_module modules/mod_foo.so
55 #
56 Include conf.modules.d/*.conf
57
58 #
59 # If you wish httpd to run as a different user or group,you must run
60 # httpd as root initially and it will switch.
61 #
62 # User/Group: The name (or #number) of the user/group to run httpd as.
63 # It is usually good practice to create a dedicated user and group for
64 # running httpd,as with most system services.
65 #
66 User apache
67 Group apache

68
69 # 'Main' server configuration
70 #
71 # The directives in this section set up the values used by the 'main'
72 # server,which responds to any requests that aren't handled by a
73 # <VirtualHost> definition. These values also provide defaults for
74 # any <VirtualHost> containers you may define later in the file.
75 #
76 # All of these directives may appear inside <VirtualHost> containers,
77 # in which case these default settings will be overridden for the
78 # virtual host being defined.
79 #
80
81 #
82 # ServerAdmin: Your address,where problems with the server should be
83 # e-mailed. This address appears on some server-generated pages,such
84 # as error documents. e.g. admin@your-domain.com
85 #
86 ServerAdmin root@localhost
87
88 #
89 # ServerName gives the name and port that the server uses to identify itself.
90 # This can often be determined automatically,but we recommend you specify
91 # it explicitly to prevent problems during startup.
92 #
93 # If your host doesn't have a registered DNS name,enter its IP address here.
94 #
95 ServerName corp.contoso.org:80
96
97 #
98 # Deny access to the entirety of your server's filesystem. You must
99 # explicitly permit access to web content directories in other
100 # <Directory> blocks below.
101 #
102 <Directory />
103 AllowOverride none
104 Require all denied
105 </Directory>
106
107 #
108 # Note that from this point forward you must specifically allow
109 # particular features to be enabled - so if something's not working as
110 # you might expect,make sure that you have specifically enabled it
111 # below.
112 #
113
114 #
115 # DocumentRoot: The directory out of which you will serve your
116 # documents. By default,all requests are taken from this directory,but
117 # symbolic links and aliases may be used to point to other locations.
118 #
119 DocumentRoot "/var/www/html"
120
121 #
122 # Relax access to content within /var/www.
123 #
124 <Directory "/var/www">
125 AllowOverride None
126 # Allow open access:
127 Require all granted
128 </Directory>
129
130 # Further relax access to the default document root:
131 <Directory "/var/www/html">
132 #
133 # Possible values for the Options directive are "None","All",
134 # or any combination of:
135 # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
136 #
137 # Note that "MultiViews" must be named *explicitly* --- "Options All"
138 # doesn't give it to you.
139 #
140 # The Options directive is both complicated and important. Please see
141 # http://httpd.apache.org/docs/2.4/mod/core.html#options
142 # for more information.
143 #
144 Options Indexes FollowSymLinks
145
146 #
147 # AllowOverride controls what directives may be placed in .htaccess files.
148 # It can be "All","None",or any combination of the keywords:
149 # Options FileInfo AuthConfig Limit
150 #
151 AllowOverride None
152
153 #
154 # Controls who can get stuff from this server.
155 #
156 Require all granted
157 </Directory>
158
159 #
160 # DirectoryIndex: sets the file that Apache will serve if a directory
161 # is requested.
162 #
163 <IfModule dir_module>
164 DirectoryIndex index.html
165 </IfModule>
166
167 #
168 # The following lines prevent .htaccess and .htpasswd files from being
169 # viewed by Web clients.
170 #
171 <Files ".ht*">
172 Require all denied
173 </Files>
174
175 #
176 # ErrorLog: The location of the error log file.
177 # If you do not specify an ErrorLog directive within a <VirtualHost>
178 # container,error messages relating to that virtual host will be
179 # logged here. If you *do* define an error logfile for a <VirtualHost>
180 # container,that host's errors will be logged there and not here.
181 #
182 ErrorLog "logs/error_log"
183
184 #
185 # LogLevel: Control the number of messages logged to the error_log.
186 # Possible values include: debug,info,notice,warn,crit,
187 # alert,emerg.
188 #
189 LogLevel warn
190
191 <IfModule log_config_module>
192 #
193 # The following directives define some format nicknames for use with
194 # a CustomLog directive (see below).
195 #
196 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
197 LogFormat "%h %l %u %t \"%r\" %>s %b" common
198
199 <IfModule logio_module>
200 # You need to enable mod_logio.c to use %I and %O
201 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
202 </IfModule>
203
204 #
205 # The location and format of the access logfile (Common Logfile Format).
206 # If you do not define any access logfiles within a <VirtualHost>
207 # container,they will be logged here. Contrariwise,if you *do*
208 # define per-<VirtualHost> access logfiles,transactions will be
209 # logged therein and *not* in this file.
210 #
211 #CustomLog "logs/access_log" common
212
213 #
214 # If you prefer a logfile with access,agent,and referer information
215 # (Combined Logfile Format) you can use the following directive.
216 #
217 CustomLog "logs/access_log" combined
218 </IfModule>
219
220 <IfModule alias_module>
221 #
222 # Redirect: Allows you to tell clients about documents that used to
223 # exist in your server's namespace,but do not anymore. The client
224 # will make a new request for the document at its new location.
225 # Example:
226 # Redirect permanent /foo http://www.example.com/bar
227
228 #
229 # Alias: Maps web paths into filesystem paths and is used to
230 # access content that does not live under the DocumentRoot.
231 # Example:
232 # Alias /webpath /full/filesystem/path
233 #
234 # If you include a trailing / on /webpath then the server will
235 # require it to be present in the URL. You will also likely
236 # need to provide a <Directory> section to allow access to
237 # the filesystem path.
238
239 #
240 # ScriptAlias: This controls which directories contain server scripts.
241 # ScriptAliases are essentially the same as Aliases,except that
242 # documents in the target directory are treated as applications and
243 # run by the server when requested rather than as documents sent to the
244 # client. The same rules about trailing "/" apply to ScriptAlias
245 # directives as to Alias.
246 #
247 ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
248
249 </IfModule>
250
251 #
252 # "/var/www/cgi-bin" should be changed to whatever your ScriptAliased
253 # CGI directory exists,if you have that configured.
254 #
255 <Directory "/var/www/cgi-bin">
256 AllowOverride None
257 Options None
258 Require all granted
259 </Directory>
260
261 <IfModule mime_module>
262 #
263 # TypesConfig points to the file containing the list of mappings from
264 # filename extension to MIME-type.
265 #
266 TypesConfig /etc/mime.types
267
268 #
269 # AddType allows you to add to or override the MIME configuration
270 # file specified in TypesConfig for specific file types.
271 #
272 #AddType application/x-gzip .tgz
273 #
274 # AddEncoding allows you to have certain browsers uncompress
275 # information on the fly. Note: Not all browsers support this.
276 #
277 #AddEncoding x-compress .Z
278 #AddEncoding x-gzip .gz .tgz
279 #
280 # If the AddEncoding directives above are commented-out,then you
281 # probably should define those extensions to indicate media types:
282 #
283 AddType application/x-compress .Z
284 AddType application/x-gzip .gz .tgz
285
286 #
287 # AddHandler allows you to map certain file extensions to "handlers":
288 # actions unrelated to filetype. These can be either built into the server
289 # or added with the Action directive (see below)
290 #
291 # To use CGI scripts outside of ScriptAliased directories:
292 # (You will also need to add "ExecCGI" to the "Options" directive.)
293 #
294 #AddHandler cgi-script .cgi
295
296 # For type maps (negotiated resources):
297 #AddHandler type-map var
298
299 #
300 # Filters allow you to process content before it is sent to the client.
301 #
302 # To parse .shtml files for server-side includes (SSI):
303 # (You will also need to add "Includes" to the "Options" directive.)
304 #
305 AddType text/html .shtml
306 AddOutputFilter INCLUDES .shtml
307 </IfModule>
308
309 #
310 # Specify a default charset for all content served; this enables
311 # interpretation of all content as UTF-8 by default. To use the
312 # default browser choice (ISO-8859-1),or to allow the META tags
313 # in HTML content to override this choice,comment out this
314 # directive:
315 #
316 AddDefaultCharset UTF-8
317
318 <IfModule mime_magic_module>
319 #
320 # The mod_mime_magic module allows the server to use various hints from the
321 # contents of the file itself to determine its type. The MIMEMagicFile
322 # directive tells the module where the hint definitions are located.
323 #
324 MIMEMagicFile conf/magic
325 </IfModule>
326
327 #
328 # Customizable error responses come in three flavors:
329 # 1) plain text 2) local redirects 3) external redirects
330 #
331 # Some examples:
332 #ErrorDocument 500 "The server made a boo boo."
333 #ErrorDocument 404 /missing.html
334 #ErrorDocument 404 "/cgi-bin/missing_handler.pl"
335 #ErrorDocument 402 http://www.example.com/subscription_info.html
336 #
337
338 #
339 # EnableMMAP and EnableSendfile: On systems that support it,
340 # memory-mapping or the sendfile syscall may be used to deliver
341 # files. This usually improves server performance,but must
342 # be turned off when serving from networked-mounted
343 # filesystems or if support for these functions is otherwise
344 # broken on your system.
345 # Defaults if commented: EnableMMAP On,EnableSendfile Off
346 #
347 #EnableMMAP off
348 EnableSendfile on
349
350 # Supplemental configuration
351 #
352 # Load config files in the "/etc/httpd/conf.d" directory,if any.
353 IncludeOptional conf.d/*.conf


[root@contoso ~]# exit
logout
[myth@contoso ~]$

创建基于ThinkPHP 5.1 框架PHP项目 ------ moapp,退出root账户的命令模式环境安装框架并创建moapp项目:

[myth@contoso ~]$ cd /home/myth/www && composer create-project topthink/think moapp --prefer-dist

配置操作Users数据表的路由:


/home/myth/www/moapp/route/route.php

<?php
// if you use Postman to test PUT method,you must select Body and x-www-form-urlencoded to auto config header

Route::get('users/:id','index/User/getUserById'); // GET http://mo.com/users/2
Route::post('users','index/User/addUser'); // POST http://mo.com/users
Route::delete('users/:id','index/User/deleteUserById'); // DELETE http://mo.com/users/2
Route::put('users','index/User/updateUserById'); // PUT http://mo.com/users
Route::get('users','index/User/index'); // GET http://mo.com/users
return [

];

实现控制器操作数据库Users表的方法:


/home/myth/www/moapp/application/index/controller/User.php
<?php
namespace app\index\controller;
use think\Controller;
use think\Request;
use think\Db;

class User extends Controller {

public function index() {
$users = Db::table('users')->select();
return json($users);
}

public function getUserById($id) {
//$user = Db::name('users')->where('id',$id)->find();
// find() method to query format json:
// {"id":2,"name":"Jason","email":"jason@sina.com","mobile":"1380013800"}
// if you use find() method,then Andorid&iPhone will throw a TypeError: data.map is not a function
$user = Db::name('users')->where('id',$id)->select();
// select() method to query format json:
// [{"id":2,"mobile":"1380013800"}]
return json($user);
}

public function addUser(Request $request) {
$name = $request->param('name');
$email = $request->param('email');
$mobile = $request->param('mobile');
$user = ['name' => $name,'email' => $email,'mobile' => $mobile];
// 启动事务
Db::startTrans();
try {
Db::name('users')->insert($user);
// 提交事务
Db::commit();
} catch (Exception $ex) {
// 回滚事务
Db::rollback();
}
}

public function deleteUserById($id) {
// 启动事务
Db::startTrans();
try {
Db::name('users')->where('id',$id)->delete();
// 提交事务
Db::commit();
} catch (Exception $ex) {
// 回滚事务
Db::rollback();
}
return json(['rows'=>'successfully']);
}

public function updateUserById(Request $request) {
$id = $request->param('id');
$name = $request->param('name');
$email = $request->param('email');
$mobile = $request->param('mobile');
$user = ['name' => $name,'mobile' => $mobile];
// 启动事务
Db::startTrans();
try {
Db::table('users')->where('id',$id)->update($user);
// 提交事务
Db::commit();
} catch (Exception $ex) {
// 回滚事务
Db::rollback();
}
}

}

配置Apache服务器:

[myth@contoso ~]$ cat > /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.123.198 mo.com


[myth@contoso ~]$ cat > /etc/httpd/conf.d/httpd-vhosts.conf

<Directory "/home/myth/www/moapp">
Options +Indexes +FollowSymLinks
Order allow,deny
Allow from all
AllowOverride All
Require all granted
</Directory>
<VirtualHost *:80>
ServerAdmin zhengzizhi@126.com
DocumentRoot "/home/myth/www/moapp/public"
ServerName mo.com
ServerAlias mo.com
ErrorLog "/home/myth/log/httpd/mo-com-error_log"
CustomLog "/home/myth/log/httpd/mo-com-access_log" common
</VirtualHost>
<Directory "/home/myth/www/moapp">
Options +Indexes +FollowSymLinks
Order allow,deny
Allow from all
AllowOverride All
Require all granted
</Directory>
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/ca-app.crt
SSLCertificateKeyFile /etc/pki/tls/private/ca-app.key
# SSLCertificateChainFile /etc/pki/tls/certs/ca-app.pem
ServerAdmin zhengzizhi@126.com
DocumentRoot "/home/myth/www/moapp/public"
ServerName mo.com
ServerAlias mo.com
ErrorLog "/home/myth/log/httpd/mo-com-s-error_log"
CustomLog "/home/myth/log/httpd/mo-com-s-access_log" common
</VirtualHost>

[myth@contoso ~]$ su -
Password:
Last login: Mon Apr 2 14:11:31 CST 2018 on pts/1
[root@contoso ~]# lsof -i:80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
httpd 1069 root 4u IPv6 23009 0t0 TCP *:http (LISTEN)
httpd 1315 myth 4u IPv6 23009 0t0 TCP *:http (LISTEN)
httpd 1316 myth 4u IPv6 23009 0t0 TCP *:http (LISTEN)
httpd 1317 myth 4u IPv6 23009 0t0 TCP *:http (LISTEN)
httpd 1318 myth 4u IPv6 23009 0t0 TCP *:http (LISTEN)
httpd 1319 myth 4u IPv6 23009 0t0 TCP *:http (LISTEN)
httpd 2860 myth 4u IPv6 23009 0t0 TCP *:http (LISTEN)
httpd 18468 myth 4u IPv6 23009 0t0 TCP *:http (LISTEN)
httpd 18688 myth 4u IPv6 23009 0t0 TCP *:http (LISTEN)
[root@contoso ~]# systemctl restart httpd && systemctl status httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
Active: active (running) since Tue 2018-04-03 23:44:21 CST; 13ms ago
Docs: man:httpd(8)
man:apachectl(8)
Process: 47406 ExecStop=/bin/kill -WINCH ${MAINPID} (code=exited,status=0/SUCCESS)
Main PID: 47415 (httpd)
Status: "Processing requests..."
CGroup: /system.slice/httpd.service
├─47415 /usr/sbin/httpd -DFOREGROUND
├─47416 /usr/sbin/httpd -DFOREGROUND
├─47417 /usr/sbin/httpd -DFOREGROUND
├─47419 /usr/sbin/httpd -DFOREGROUND
├─47420 /usr/sbin/httpd -DFOREGROUND
└─47421 /usr/sbin/httpd -DFOREGROUND

Apr 03 23:44:21 contoso.org systemd[1]: Starting The Apache HTTP Server...

Apr 03 23:44:21 contoso.org systemd[1]: Started The Apache HTTP Server.


配置macOS系统的hosts文件 ------ macOS这台机器是react-native这台开发机器

myths-Mac:~ myth$ sudo su

Password:
sh-3.2# cat > /etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
192.168.123.198 mo.com

创建项目 ------ zigoo

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

接下来我们要在macOS系统的命令行终端里通过命令去修改Android手机模拟器它的操作系统对应的hosts文件,修改它就有点特别啦,请按我的顺序执行指令,注意可能你的设备名称显示出来跟我的不一样,你需要开启两个终端窗口,一个用来首先用来启动安卓模拟用的,另外一个用来修改hosts文件用的,请特别注意192.168.123.198这个IP改成你实际的IP地址,本范例是在VMWare workstation pro 12 中实验的 1台PHP部署环境 用的系统是CentOS 7.2 另外一台开发react-native的机器是macOS系统

如果你已经有安卓模拟打开了 就必须关闭它们,那我们先来用命令以可写信息的模式来启动安卓模拟器吧:

电脑macOS系统中的命令终端窗口1,你发现自己emulator命令不是全局目录命令,

请参考我其它篇幅中讲的1条指令搞定配置部分

myths-Mac:~ emulator -list-avds #列出所有模拟器

Nexus_5X_API_23

myths-Mac:~ emulator -avd Nexus_5X_API_23 -writable-system #以可写信息的模式来启动安卓模拟器

电脑macOS系统中的命令终端窗口2,开始修改手机的hosts文件

myths-Mac:~ myth$ adb shell cat /etc/hosts

127.0.0.1 localhost
::1 ip6-localhost
myths-Mac:~ myth$ adb root
adbd is already running as root
myths-Mac:~ myth$ adb remount
remount succeeded
myths-Mac:~ myth$ adb pull /system/etc/hosts ~/Desktop/hosts
/system/etc/hosts: 1 file pulled. 0.0 MB/s (56 bytes in 0.003s)
myths-Mac:~ myth$ echo '192.168.123.198 mo.com' >> ~/Desktop/hosts
myths-Mac:~ myth$ cat ~/Desktop/hosts
127.0.0.1 localhost
::1 ip6-localhost

192.168.123.198 mo.com
myths-Mac:~ myth$ adb push ~/Desktop/hosts /system/etc/hosts
/Users/myth/Desktop/hosts: 1 file pushed. 0.0 MB/s (81 bytes in 0.005s)
myths-Mac:~ myth$ adb shell cat /etc/hosts
127.0.0.1 localhost
::1 ip6-localhost

192.168.123.198 mo.com

我们可以用手机模拟器中的浏览器测试一下 http://mo.com/users是否能跨系统访问:

最后我把手机端的react-native项目代码贴出来

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://mo.com/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://mo.com/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://mo.com/users/'+ this.uid,
})
console.log(this.state.apiData);
})
.catch((error) => {
console.warn(error);
}).done();
this.uid = null;
}

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

onPutUser = () => {
fetch('http://mo.com/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,
}

});

如果你想掌握快速调试react-native的技巧,请照我贴的图和上面的文字说明操作吧,会快速调试代码是自己快速解决问题最基本的能力 一定要学会掌握,不然一旦出问题你就傻眼了

如果你不喜欢使用fetch的方式去操作数据库的Restful API接口,我们还可以使用axios插件去操作数据库的Restful API接口

$ cd /Users/myth/zigoo && yarn add axios #安装 axios 插件

App.js 完整的代码如下:

import React,{ Component } from 'react';import { StyleSheet,Text,TextInput,View,ScrollView,TouchableHighlight} from 'react-native';import axios from 'axios';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 = () => { axios.get('http://mo.com/users') .then(response => { this.setState({ apiData: response.data }); }) .catch(function (error) { console.log(error); }); this.uid = null; } onPostUser = () => { axios({ method: 'post',url: 'http://mo.com/users',headers: { 'Accept': 'application/json','Content-Type': 'application/json' },data: { name: this.name,mobile: this.mobile } }).then((response) => { //接收restful-api新增记录成功还返回一条成功的提示消息 this.setState({ naData: response.data,}) console.log(this.state.naData); }) .catch((error) => { console.warn(error); }) this.uid = null; this.name = null; this.email = null; this.mobile = null; } onGetUser = () => { axios.get('http://mo.com/users/'+ this.uid) .then(response => { this.setState({ apiData: response.data }); }) .catch(function (error) { console.log(error); }); this.uid = null; } onDeleteUser = () => { axios({ method: 'delete',url: 'http://mo.com/users/'+ this.uid }).then((response) => { //接收restful-api删除记录成功还返回一条成功的提示消息 this.setState({ naData: response.data,}) console.log(this.state.naData); }) .catch((error) => { console.warn(error); }) this.uid = null; } onPutUser = () => { axios({ method: 'put',id: this.uid } }).then((response) => { //接收restful-api更新记录成功还返回一条成功的提示消息 this.setState({ naData: response.data,}) console.log(this.state.naData); }) .catch((error) => { console.warn(error); }) 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,marginTop: 10}}> My App Users </Text> <View style={{height: 2,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',fontSize:16,}});

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 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