
ååã瀺ãããã«ããã®èšäºã§ã¯Androidçšã®React Nativeã¢ããªã±ãŒã·ã§ã³ãäœæããããã»ã¹ãæ€èšããŸãã ããã¹ãããã¯ã¹ãããã°ç°¡åã§ãã ããã§ããã±ã¢ã³ã®1ã€ã®ååãå
¥åããå¿
èŠããããŸããã¢ããªã±ãŒã·ã§ã³ã¯ãåä¿¡ããããŒã¿ã«é¢ãã詳现æ
å ±ã衚瀺ããããã¹ãèªã¿äžãæ©èœã䜿çšããŠèªã¿åããŸãã
Android SDKã®ã€ã³ã¹ããŒã«ã
React Nativeããããžã§ã¯ãã®äœæããã®ä»ã®éçºããŒã«ã«ã€ããŠã¯è§ŠããŸããã ããããReact Nativeã䜿çšããŠã¢ããªã±ãŒã·ã§ã³ãäœæããåããŠã®çµéšã§ãããšæ³å®ãããããåã³ãŒãã詳ããèŠãŠãããŸãã
ãµãŒããŒäœæ
ãŸããã¢ããªã±ãŒã·ã§ã³ã®ãµãŒããŒã³ã³ããŒãã³ããäœæããå¿
èŠããããŸãã PHPã§äœæããCouchDBã¯ããŒã¿ããŒã¹ãšããŠæ©èœããŸãã ã€ã³ã¹ããŒã«æé ïŒ
PHPããã³
CouchDB ã€ã³ã¹ããŒã«ãšæ§æã®åŸãããŒã¿ããŒã¹ãå®è¡ãããŠããããšã確èªããå¿
èŠããããŸãã ãããè¡ãã«ã¯ã
curl localhost:5984
ãå®è¡ãã次ã®ãããªãã®ãååŸããŸãã
{"couchdb":"Welcome","uuid":"xxxxxxxxxxxxxxxx","version":"1.6.0","vendor":{"name":"Ubuntu","version":"15.10"}}
CouchDB管çã·ã¹ãã ã§ãã
Futonã«ã¢ã¯ã»ã¹ããã«ã¯ã
httpïŒ// localhostïŒ5984 / _utilsããã©ãŠã¶ãŒã§éã
ãŸã ã [
ããŒã¿ããŒã¹ã®äœæ]ãã¯ãªãã¯ããŠã
Pokemon APIããåä¿¡ãã詳现ããŒã¿ãä¿åããããŒã¿ããŒã¹ãäœæããŸãã ããŒã¹
pokedexã«ååã
ä»ã ã[
äœæ ]ãã¯ãªãã¯ã
ãŸã ã React NativeããAPIã«çŽæ¥ã¢ã¯ã»ã¹ã§ããŸããããããã¯ãŒã¯ãã©ãã£ãã¯ãå¢å ããŸãã ãŸããããŒã¿ããŒã¹ã«ãã¹ãŠãä¿åãããšã1åã®èŠæ±ã§ãã€ã§ãããŒã¿ãååŸã§ããŸãã
ããŒã¿ä¿å
次ã«ããµãŒããŒã³ã³ããŒãã³ãã®äœæã«çŽæ¥é²ã¿ãŸãã WebãµãŒããŒãã©ã«ããŒå
ã«äœæ¥ãã©ã«ããŒãäœæãããã®äžã«
composer.jsonãã¡ã€ã«ãäœæããŠã³ãŒããè¿œå ããŸãã
{ "require": { "doctrine/couchdb-odm": "@dev" }, "minimum-stability": "dev", "prefer-stable": true }
ããã¯ã
doctrine/couchdb-odm
ã©ã€ãã©ãªãŒããããžã§ã¯ãã®äžéšã«ãªã£ãããšãæå³ããŸãã 圌女ã¯ãPHPã§CouchDBãæäœããã®ãæäŒã£ãŠãããŸãã ãããã€ã³ã¹ããŒã«ããã«ã¯ã
composer install
ãŸãã
äœæ¥ãã©ã«ããŒå
ã«
pokemon.phpãã¡ã€ã«ãäœæã
ãã³ãŒãã
貌ãä»ããŸãïŒ
<?php require 'vendor/autoload.php'; set_time_limit(0); $client = \Doctrine\CouchDB\CouchDBClient::create(array('dbname' => 'pokedex')); $pokedex = file_get_contents('http://pokeapi.co/api/v1/pokedex/1/'); $pokedex_data = json_decode($pokedex, true); foreach($pokedex_data['pokemon'] as $row){
äžèšã®ã³ãŒããæ€èšããŠãã ããã ãŸããèªåããŒããã¡ã€ã«ãè¿œå ãããŸãã Composerã䜿çšããŠã€ã³ã¹ããŒã«ãããã¹ãŠã®ã©ã€ãã©ãªãèªåçã«ããŒãããŸãã 次ã«ã
set_time_limit
ãŒãã«
set_time_limit
ããŸãã å®éãPHPã¹ã¯ãªããã§ã¯ãããã©ã«ãã§å®è¡æéãå¶éããããã®æéã®çµããã«ã¹ã¯ãªãããäžæãããŸãã äžèšã®ãã©ã¡ãŒã¿ãŒããŒãã«ããŠãæéå¶éããªãã«ããŸãã
ãã®èšäºã®å·çæç¹ã§ã¯721ã®ãã±ã¢ã³ããããããããã«ã€ããŠ3ã€ã®HTTPãªã¯ãšã¹ããå®äºããŠã詳现ãªããŒã¿ã説æãã¹ãã©ã€ããååŸããå¿
èŠããããŸãã
<?php require 'vendor/autoload.php'; set_time_limit(0);
CouchDBã¯ã©ã€ã¢ã³ããåæåããããŒã¿ããŒã¹ã®ååãå
¥åããŸãã
<?php $client = \Doctrine\CouchDB\CouchDBClient::create(array('dbname' => 'pokedex'));
file_get_contents
é¢æ°ã䜿çšããŠãAPIãããã±ã¢ã³ã®å®å
šãªãªã¹ããååŸããŸãã ããŒã¿ã¯JSON圢åŒã§è¿ããããããããã«äœæ¥ãé²ããã«ã¯ãããŒã¿ãé
åã«å€æããå¿
èŠããããŸãã
<?php $pokedex = file_get_contents('http://pokeapi.co/api/v1/pokedex/1/'); $pokedex_data = json_decode($pokedex, true);
ãã¹ãŠã®çµæã«å¯ŸããŠãµã€ã¯ã«ãå®è¡ããŸãã
<?php foreach($pokedex_data['pokemon'] as $row){ ... }
åãã±ã¢ã³ã®ã«ãŒãå
ã§ã
resource_uri
ã䜿çšããããã䜿çšããŠè©³çŽ°ããŒã¿ãè¿ãURLãäœæããŸãã
<?php
åã®ãªã¯ãšã¹ãã«å¿ããŠåä¿¡ããããŒã¿ã䜿çšããŠããã±ã¢ã³ãšãã®ã¹ãã©ã€ãã®èª¬æã®ãªã¯ãšã¹ããäœæããŸãã
<?php
åä¿¡ããæ
å ±ãCouchDBã«ä¿åããŸãã
<?php $client->postDocument($pokemon);
ä¿åãéå§ããã«ã¯ããã©ãŠã¶ãŒã§
pokemon.phpãã¡ã€ã«ãéããŸãã ããã«ã¯å°ãæéãããããŸãããä»ã®ãšããã¯æ¬¡ã®ã¹ãããã«é²ãããšãã§ããŸãã
ããŒã¿æœåº
CouchDBããããŒã¿ãååŸããã«ã¯ããã¥ãŒãäœæããå¿
èŠããããŸãã
äœæããããŒã¿ããŒã¹ã«ç§»åããããããããŠã³ã¡ãã¥ãŒã§[
衚瀺 ]ãã¯ãªãã¯ãã[
äžæãã¥ãŒ ]ãéžæããŸãã
ãããé¢æ°ã®ããã¹ãããã¯ã¹ã®äžã«ãã³ãŒãã貌ãä»ããŸãã
function(doc) { emit(doc.name, null); }
次ã«ãã
å®è¡ããã¿ã³ãã¯ãªãã¯ããŠãããŒã¿ã®è¡šç€ºæ¹æ³ã確èªããŸãã

[ååãä»ããŠ
ä¿å]ãã¯ãªãã¯ãã[
ãã¶ã€ã³ããã¥ã¡ã³ã] ãã£ãŒã«ãã«
ãã±ã¢ã³ããŒã¹ã®ååãå
¥åãã
[ãã¥ãŒå] ãã£ãŒã«ãã« by_nameãå
¥åã
ãŸã ã äœæ¥ãã©ã«ããŒã«æ»ãã
get.phpãã¡ã€ã«ãäœæããŠã³ãŒããå
¥åããŸãã
<?php require 'vendor/autoload.php'; $client = \Doctrine\CouchDB\CouchDBClient::create(array('dbname' => 'pokedex')); $pokemon = $_GET['name']; $query = $client->createViewQuery('pokemon', 'by_name'); $query->setKey($pokemon); $query->setReduce(false); $query->setIncludeDocs(true); $result = $query->execute(); if(!empty($result[0])){ $data = $result[0]; echo json_encode($data); }else{ $result = array('no_result' => true); echo json_encode($result); }
ãããå解ããŠã¿ãŸãããã ãŸããã¢ããªã±ãŒã·ã§ã³ããéä¿¡ããããã±ã¢ã³ã®ååãååŸããŸãã
<?php $pokemon = $_GET['name'];
createViewQuery
ã¡ãœãããåŒã³åºãããšã«ããããã¥ãŒ
createViewQuery
äœæãã
Design document
View name
ãš
View name
ãèšå®ãããªãã·ã§ã³ã®å€ã決å®ããŸãã setKeyã¡ãœããã¯ããªã¯ãšã¹ããèšè¿°ããããã«äœ¿çšãããŸãã ãã¥ãŒããåä¿¡ããããŒã¿ã®ãã£ã«ã¿ãªã³ã°ã¯
setReduce
ã䜿çšããŠå®è¡ããã
setIncludeDocs
ã¯è¿ãããçµæããšã«ç¹å®ã®ããã¥ã¡ã³ããè¿œå ããŸãã äžã®ã¹ã¯ãªãŒã³ã·ã§ããããããã¥ã¡ã³ããæ¬ èœããŠããããšã«æ°ã¥ãããããããŸããã å®éã«ã¯ã
setIncludeDocs
ã
setIncludeDocs
ããåŒæ°ã
true
å Žåãããã©ã«ãã®ããã¥ã¡ã³ãã¯ã
pokemon.phpãã¡ã€ã«ã«
ã¢ã¯ã»ã¹ãããšãã«ä¿åãããããã¥ã¡ã³ãã§ãã
<?php $query = $client->createViewQuery('pokemon', 'by_name');
次ã«ãçµæã確èªããå¿
èŠããããŸãã ååšããå Žåã¯JSONããŒãžã§ã³ãè¿ããååšããªãå Žåã¯ããŒã¿ã®äžè¶³ã«é¢ããã¡ãã»ãŒãžãè¿ããŸãã
<?php if(!empty($result[0])){ $data = $result[0]; echo json_encode($data); }else{ $result = array('no_result' => true); echo json_encode($result); }
ããŒã«ã«ãã·ã³ã§äœæ¥ããŠããå Žåã¯ã
Ngrokã䜿çšããŠãµãŒããŒã®ã€ã³ã¿ãŒãããã¢ã¯ã»ã¹ãéãããšãã§ããŸãã ãŸãã¯ãå
éšIPã䜿çšããŸããåŸã§ãã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšãããŸãã
ã¢ããªã±ãŒã·ã§ã³äœæ
äŸåé¢ä¿ã®ã€ã³ã¹ããŒã«
React Nativeã§æ°ãããããžã§ã¯ããåæåããããšããå§ããŸãããã
react-native init Pokedex
æäœãå®äºããããnpmã䜿çšããŠäŸåé¢ä¿ãã€ã³ã¹ããŒã«ããŸãã
cd Pokedex
npm install lodash react-native-android-speech react-native-gifted-spinner --save
ãã®ã³ãŒãã®æ©èœïŒ
lodash
ããã¹ãã倧æåã«å€æããé
åããç¹å®ã®ããŒã¿ãæœåºããããã«äœ¿çšãããŸããreact-native-android-speech
ããã¹ãã®èª¬æãé³å£°ã«å€æããŸããreact-native-gifted-spinner
ãããã¯ãŒã¯èŠæ±ãå®è¡ããéã®èªã¿èŸŒã¿ã¢ãã¡ãŒã·ã§ã³ã衚瀺ããŸãã
node_modules / react-native / node_modulesãã©ã«ããŒã«ã€ã³ã¹ããŒã«ãããŠãããã¹ãŠã®ã¢ãžã¥ãŒã«ã衚瀺ã§ã
ãŸã ã
ã€ã³ã¹ããŒã«ãå®äºãããã
React Native Android Speechãªããžããªã«ç§»åããæ瀺ã«åŸã£ãŠæ§æããŸãã
ãããã¯ãŒã¯ã¯ãšãª
React Nativeãããžã§ã¯ãã®ã«ãŒããã£ã¬ã¯ããªã§ã
srcãã©ã«ããŒãäœæãããã®äžã«
api.jsãã¡ã€ã«ãäœæãã
ããã«ã³ãŒãã
è¿œå ããŸãã
module.exports = function(pokemon){ var url = 'http://192.168.xxx.xxx/pokedex/get.php?name=' + pokemon; return fetch(url).then(function(response){ return response.json(); }).then(function(json){ return json; }); }
fetch
ã¡ãœããã¯ããµãŒããŒããããŒã¿ãæœåºããæ©èœããšã¯ã¹ããŒãããŸãã ãã®ããã«ããŠãReact Nativeã¯ãããã¯ãŒã¯èŠæ±ãäœæããŸãã ãã®ã¡ãœããã¯ãURLãåä¿¡ããŠââãªã¯ãšã¹ããäœæãã
then
ã¡ãœããã䜿çšããããšãçŽæããã³ãŒã«ããã¯é¢æ°ã䜿çšããŠå¿çãåä¿¡ããŸãã
å¿çã§åä¿¡ããããŒã¿ãããã®ãŸãŸã䜿çšããããšã¯ã§ããŸãããæåã«ããããã
response
ãªããžã§ã¯ãããå©çšå¯èœãª
json
ã¡ãœããã«æž¡ãå¿
èŠããããŸãã ãããããå¥ã®
then
ã¡ãœãããåŒã³åºãããšã§ãJSON圢åŒã®ããŒã¿ãæ¢ã«ååŸã§ããŸãã ãããã¯åŒæ°ãšããŠã³ãŒã«ããã¯é¢æ°ã«æž¡ãããåŒæ°ãšããŠè¿ãããŸãã
fetch
ã¡ãœããã®æ»ãçµæãçŽæã§ããããšã«æ³šæããŠãã ããã ãããã£ãŠãåŸã§ã¡ã€ã³ã¹ã¯ãªãããããã®ã¢ãžã¥ãŒã«ãåŒã³åºãå ŽåãJSONããŒã¿ã«ã¢ã¯ã»ã¹ããåã«
then
ã¡ãœãããå床䜿çšããå¿
èŠããããŸãã
泚 ïŒ
http://192.168.xxx.xxx/
:
http://192.168.xxx.xxx/
ãåè¿°ã®IPã¢ãã¬ã¹ãŸãã¯ãã¡ã€ã³åã«å€æŽããŠãã ããã pokedexã¯Webã€ã³ããã¯ã¹å
ã®ãã©ã«ããŒã§ããããšãå¿ããªãã§ãã ããã
ã¡ã€ã³ã¢ããªã±ãŒã·ã§ã³ãã¡ã€ã«
index.android.jsãã¡ã€ã«ãéããŸãã ããã€ãã®ããã©ã«ãã³ãŒããå¿
èŠã§ãããã¹ãŠåé€ããŠãã ããã
åãã¡ã€ã«ã®å
é ã§ãå³æ Œã¢ãŒããæå¹ã«ããŸãã ããã¯ãå€ãåæåãããåã®å€æ°å®çŸ©ã®æ¬ åŠãªã©ãäžè¬çãªééããé¿ããã®ã«åœ¹ç«ã¡ãŸãã
React Nativeãšè¿œå ã®ãããžã§ã¯ãäŸåé¢ä¿ãã€ã³ããŒãããŸãã
'use strict'; var React = require('react-native'); var tts = require('react-native-android-speech') var GiftedSpinner = require('react-native-gifted-spinner'); var _ = require('lodash');
å¿
èŠãªãã¹ãŠã®ã³ã³ããŒãã³ããšAPIãåæåããŸãã
var { AppRegistry, StyleSheet, Text, TextInput, View, Image, ListView } = React;
React Nativeã§ã¯ãããŸããŸãªã³ã³ããŒãã³ããšAPIã䜿çšã§ããŸãã ããã©ã«ãã§ã¯ããŒããããªããããå¿
èŠãªãã®ããã¹ãŠå
·äœçã«æå®ããå¿
èŠããããŸãã ãããããŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹èŠçŽ ãšèŠãªãããšãã§ããŸãã WebããŒãžã«ããã¹ããã£ãŒã«ãããªã¹ããããŒãã«ãç»åãã¿ããªã©ããããšããŸãã React Nativeã§ã¯ããããã®ã€ã³ã¿ãŒãã§ãŒã¹èŠçŽ ã¯ãã¹ãŠã³ã³ããŒãã³ãã§ãã ããšãã°ã
ç»å㮠衚瀺ãã¹ã¯ããŒã«ããŒã®è¡šç€º ã
ãªã¹ãã®äœæãªã©ã®ããã®ã³ã³ããŒãã³ãããã
ãŸã ã
React APIã¯ãã«ã¡ã©ãããã·ã¥éç¥ãªã©ã®ããŸããŸãªããã€ã¹æ©èœã«ã¢ã¯ã»ã¹ããããã«äœ¿çšãããŸãã äžéšã®APIã䜿çšããããšã¯ã»ãšãã©ãããŸãããããã¹ãŠã®ãããžã§ã¯ãã§äžéšãå¿
èŠã§ãã äŸã«ã¯ã
StyleSheetããã³
AppRegistryãå«ãŸã
ãŸã ã
以äžã¯ãã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšããã³ã³ããŒãã³ããšAPIã®ç°¡åãªèª¬æã§ãã
AppRegistry
ã«ã¹ã¿ã ã³ã³ããŒãã³ããç»é²ããŸãã React Nativeã®ãã¹ãŠã¯ã³ã³ããŒãã³ãã§ãããã³ã³ããŒãã³ãã¯ããã«å°ããªã³ã³ããŒãã³ãã§æ§æã§ããŸããStyleSheet
ã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšãããã¹ã¿ã€ã«ãèšè¿°ããããã«äœ¿çšãããŸããText
-ããã¹ãã®è¡šç€ºãæ
åœããŸããTextInput
ããã¹ããã£ãŒã«ãã®äœæã«äœ¿çšãããŸããView
-ãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ãäœæãããšãã®ã¡ã€ã³ã³ã³ããŒãã³ãã äžè¬ã«ã©ãããŒãšããŠäœ¿çšãããŸããImage
-ç»åã衚瀺ããŸããListView
衚瀺ããŸãã
次ã«ã以åã«äœæãã
src / api.jsãã¡ã€ã«ãã€ã³ããŒãã
ãŸã ã ããã«ããã
api
ã¡ãœãããåŒã³åºããŠãããã¯ãŒã¯èŠæ±ãèš±å¯ããŸãã
var api = require('./src/api.js');
ãã¹ãŠã®ã€ã³ã¿ãŒãã§ã€ã¹ãšã¢ããªã±ãŒã·ã§ã³ããžãã¯ãå«ãæ°ããã«ã¹ã¿ã ã³ã³ããŒãã³ããReactã§äœæããŸãã
var Pokedex = React.createClass({ ... });
ã¯ã©ã¹å
ã®ç¶æ
ãåæåããŸãã React Nativeã®ãç¶æ
ããšã¯ãã³ã³ããŒãã³ãå
šäœã§å©çšå¯èœãªããŒã¿ãä¿åããæ¹æ³ãæå³ããŸãã
query
-ãŠãŒã¶ãŒãå
¥åããããã¹ããhasResult
æ€çŽ¢çµæãããããšã瀺ããŸããnoResult
æ€çŽ¢çµæããªãããšã瀺ããŸãã hasResult
ã®éãå®è¡ããŸãããçµæãªãã瀺ãã¡ãã»ãŒãžã衚瀺ãããã©ããã決å®ããããã«äœ¿çšãããŸãã æ€çŽ¢ããŸã å®è¡ãããŠããªãã¢ããªã±ãŒã·ã§ã³ã®æåã®ããŠã³ããŒãæã«ããŠãŒã¶ãŒã«ãã®ãããªå瀺ãããã«è¡šç€ºãããããšã¯æãŸãããããŸãããresult
ãµãŒããŒããåãåã£ãçŸåšã®çµæãä¿åããŸããisLoading
é²è¡ç¶æ³ããŒã衚瀺ããŸããdataSource
ãªã¹ããã¥ãŒã®ããŒã¿ãœãŒã¹ãå«ãŸããŸãã ãŸãã ListView.DataSource
æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæããã rowHasChanged
é¢æ°ãå«ããªããžã§ã¯ããrowHasChanged
ãŸãã ããŒã¿ãœãŒã¹ãå€æŽããå Žåããã®é¢æ°ã¯ListView
å
ã®è¡ãåã¬ã³ããªã³ã°ããããã«ListView
ã«æ瀺ããŸãã ãã®äŸã§ã¯ããœãŒã¹ã¯ãã±ã¢ã³ã¿ã€ãã®ãªããžã§ã¯ãã®é
åã§ãã search
æ¹æ³ãèŠããšããã®ããŒã¿ãã©ã®ããã«æäŸãããããç解ã§ããŸãã
getInitialState: function(){ return { query: null, hasResult: false, noResult: false, result: null, isLoading: false, dataSource: new ListView.DataSource({ rowHasChanged: (row1, row2) => row1 !== row2, }) } },
次ã«ã
render
ã¡ãœãããèŠãŠãã ããã 圌ã¯ããŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ã®ã¬ã³ããªã³ã°ãæ
åœããŠããŸãã
render: function() { ... },
ã€ã³ã¿ãŒãã§ã€ã¹ã¯ã¡ãœããå
ã«è¿ãããŸãã
return ( <View style={styles.container}> <View style={styles.search}> <TextInput style={styles.text_input} onChangeText={this.changeText} onSubmitEditing={this.search} placeholder="Type a pokemon name" /> </View> { this.state.hasResult && <View style={styles.result}> <View style={styles.main_details}> <Image source={{uri: this.state.result.small_photo}} style={styles.image_dimensions} resizeMode={Image.resizeMode.contain} /> <Text style={styles.main_text}>{this.state.result.name}</Text> <ListView contentContainerStyle={styles.types} dataSource={this.state.types} renderRow={this.renderType}></ListView> <View style={styles.description}> <Text style={styles.description_text}>{this.state.result.description}</Text> </View> </View> </View> } { this.state.noResult && <View style={styles.no_result}> <Text style={styles.main_text}>Pokemon not found</Text> <Text style={styles.sub_text}>Please type the exact name</Text> </View> } { this.state.isLoading && <View style={styles.loader}> <GiftedSpinner /> </View> } </View> );
ãã®ã³ãŒããåæããŸãããã ã¡ã€ã³ã³ã³ãããäœæããŸãã
<View style={styles.container}> </View>
泚 ïŒããã¯åææ¡ä»¶ã§ãã1ã€ã®ã«ãŒãã³ã³ããŒãã³ããååšããå¿
èŠããããä»ã®ãã¹ãŠã®ã³ã³ããŒãã³ãã¯ãã¹ããããŠããããã§ãã
style
å±æ§ã®å€ã¯ãã³ã³ããŒãã³ãã®ã¹ã¿ã€ã«ãèšè¿°ãããªããžã§ã¯ãã§ãã 以äžã§ã¯ã
styles
ãªããžã§ã¯ããã©ã®ããã«å®£èšãããŠãããã説æã
styles
ããçŸæç¹ã§ã¯ããªããžã§ã¯ããåŒçšç¬ŠãšããŠäœ¿çšããå ŽåãåŒçšç¬Šã䜿çšããå¿
èŠããªãããšãèŠããŠãããŠãã ããã
ã¡ã€ã³ã³ã³ããå
ã«ã¯ããã±ã¢ã³ã®ååãå
¥åããããã«èšèšãããã³ã³ããŒãã³ãããããŸãã 次ã®3ã€ã®å±æ§ããããŸãã
onChangeText
ããã¹ããã£ãŒã«ãã®ããã¹ããå€æŽããããã³ã«å®è¡ãããé¢æ°ãèšå®ããŸããonSubmitEditing
ããã¹ããããã¹ããã£ãŒã«ãã«éä¿¡ããããã³ã«å®è¡ãããé¢æ°ãèšå®ããŸããplaceholder
-å
¥åããããŒã¿ããªããšãã«è¡šç€ºãããããã¹ããèšå®ããŸãã
<View style={styles.search}> <TextInput style={styles.text_input} onChangeText={this.changeText} onSubmitEditing={this.search} placeholder="Type a pokemon name" /> </View>
次ã¯ãæ€çŽ¢çµæã衚瀺ããã³ã³ããŒãã³ãã§ãã ãã®æ§æã¯åã®ãã®ãšãããã«ç°ãªããäžæ¬åŒ§ã§å²ãŸããæåã«æ¡ä»¶ããããŸãã ããã«ãããReactã¯ç¶æ
ãçµæã«ä¿åãããŠããå Žåã«ã®ã¿ã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããŸãã ãã®ã³ã³ããŒãã³ãã®å
éšã«ã¯ããã±ã¢ã³ã®ç»åã衚瀺ãã
Image
ãšãå°ããªåç©ã®ååã®
Text
2ã€ããããŸãã 次ã¯
ListView
ã³ã³ããŒãã³ãã§ããã±ã¢ã³ã®çš®é¡ã«é¢ããæ
å ±ãå«ãŸããŠããŸãã å®éãããã€ãã®ãã±ã¢ã³ã¯è€æ°ã®çš®ã«å±ããããšãã§ããããããã®ã³ã³ããŒãã³ããå¿
èŠã§ãã æåŸã«ã
View
ã³ã³ããŒãã³ãã¯ããã±ã¢ã³ã®èª¬æã衚瀺ãã圹å²ãæãããŸãã
{ this.state.hasResult && <View style={styles.result}> <View style={styles.main_details}> <Image source={{uri: this.state.result.small_photo}} style={styles.image_dimensions} resizeMode={Image.resizeMode.contain} /> <Text style={styles.main_text}>{this.state.result.name}</Text> <ListView contentContainerStyle={styles.types} dataSource={this.state.types} renderRow={this.renderType}></ListView> <View style={styles.description}> <Text style={styles.description_text}>{this.state.result.description}</Text> </View> </View> </View> }
åã³ã³ããŒãã³ãã詳ããèŠãŠã¿ãŸãããã
Image
ã¯
source
å±æ§ãååŸããŸããããã«ãããç»åã®ãœãŒã¹ãæå®ã§ããŸãã ããã¯ããããã¯ãŒã¯ãããŒã«ã«ãã¡ã€ã«ã·ã¹ãã ããŸãã¯ã¢ããªã±ãŒã·ã§ã³ãªãœãŒã¹ããã®ç»åã§ãã ãã®å Žåããããã¯ãŒã¯ããã®ç»åã䜿çšãããããŒã¿ã¯ç¶æ
ã§ä¿åãããŸãã
resizeMode
ã¯ããã¬ãŒã ã«åãŸããªãå Žåã«ç»åã®ãµã€ãºå€æŽãèšå®ããŸãã 䜿çšãããå€ã¯
contain
ã§ãã ããã¯ãæ¯çãæªããããšãªããç»åããã¬ãŒã ã«åãŸãããšãæå³ããŸãã
<Image source={{uri: this.state.result.small_photo}} style={styles.image_dimensions} resizeMode={Image.resizeMode.contain} />
Text
ã³ã³ããŒãã³ãã¯ããã¹ãã衚瀺ããŸãã React Nativeã§ã¯ãåºåããã¹ãã¯
Text
ã³ã³ããŒãã³ãã«åãŸãå¿
èŠããããŸãã
<Text style={styles.main_text}>{this.state.result.name}</Text>
ListView
ã³ã³ããŒãã³ãã¯
ListView
衚瀺ããŸãã ããã§1ã€ã®æ³šæäºé
ããããŸãïŒ
contentContainerStyle
ã
style
å±æ§ã®ä»£ããã«ã¹ã¿ã€ã«ãå®çŸ©ããããã«äœ¿çšãããŸãã
dataSource
䜿çš
dataSource
ãšããªã¹ããã¬ã³ããªã³ã°ããããã®ããŒã¿ãœãŒã¹ã決å®ã§ãã
renderRow
ã¯ãªã¹ãå
ã®åã¢ã€ãã ãã¬ã³ããªã³ã°ãããšãã«å®è¡ãããé¢æ°ãèšå®ããŸãã
<ListView contentContainerStyle={styles.types} dataSource={this.state.types} renderRow={this.renderType}></ListView>
æ€çŽ¢çµæã衚瀺ããåŸãçµæããªãå Žåã«è¡šç€ºãããã³ã³ããŒãã³ãããããŸãã
{ this.state.noResult && <View style={styles.no_result}> <Text style={styles.main_text}>Pokemon not found</Text> <Text style={styles.sub_text}>Please type the exact name</Text> </View> }
以äžã¯ã
Gifted Spinnerã¢ãžã¥ãŒã«ã䜿çšããŠã¢ãã¡ãŒã·ã§ã³ã衚瀺ããããŠã³ããŒãã€ã³ãžã±ãŒã¿ãŒã§ãã ãã®ã€ã³ãžã±ãŒã¿ã¯ãç¶æ
ã®
isLoading
ããããã£ã
true
èšå®ãããŠããå Žåã«ã®ã¿è¡šç€ºãã
true
ã ããã¯ããããã¯ãŒã¯èŠæ±ãå®è¡ããçŽåã«è¡ãããå¿çãåä¿¡ããããšãå€ã
false
å€ãã
false
ã
{ this.state.isLoading && <View style={styles.loader}> <GiftedSpinner /> </View> }
次ã«ããªã¹ãå
ã®åã¢ã€ãã ãã¬ã³ããªã³ã°ããã¡ãœãããè¿œå ãããŸãã
ListView
ã³ã³ããŒãã³ãã®å®£èšã§ã¯ã
renderRow
å±æ§ã®å€ãšããŠäœ¿çšãããŸãã ããã¯ãŸãã«æ¹æ³ã§ãã
renderType: function(type){ return ( <View style={[styles[type.name], styles.type]}> <Text style={styles.type_text}>{type.name}</Text> </View> ); },
ListView
ã³ãŒããèŠããšã
renderRow
å±æ§ã«ã¯ã以äžã§åç
§ãã
type
ãã€ã³ããŒãä»ã«ãªãããšãããããŸãã å®éã
renderRow
ã¯é衚瀺ã®æ¹æ³ã§ããŒã¿ãèªåçã«è»¢éããŸãã
ãµãŒããŒããè¿ãããå¿çãã次ã®ããã«ã
types
ãªããžã§ã¯ãã«ã¯ãããŸããŸãªã¿ã€ãã®ãã±ã¢ã³ã«å¯Ÿå¿ãããªããžã§ã¯ãã®é
åãå«ãŸããŠããŸãã
[ { "name":"electric", "resource_uri":"\/api\/v1\/type\/13\/" } ]
type
åŒæ°ãä»ããŠ
renderType
ã¡ãœããã§ãã®ãªããžã§ã¯ãã«ã¢ã¯ã»ã¹ããŸãã ãã±ã¢ã³ã®ã¿ã€ããšã¹ã¿ã€ã«ã®ã³ã³ãããŒã«ã衚瀺ããããã«äœ¿çšãããŸãã 次ã«ãã¹ã¿ã€ã«å®£èšã§ãã¿ã€ãããšã«ç°ãªãã¹ã¿ã€ã«ãè¿œå ããå¿
èŠããããŸãã ãæ°ã¥ããããããŸãããã
View
ã³ã³ããŒãã³ãã«ã¯2ã€ã®ã¹ã¿ã€ã«å®£èšã䜿çšããŸãã ãããã£ãŠãReact Nativeã§ã¯ãåã¹ã¿ã€ã«å®£èšãé
åã«è¿œå ãããŸãã
<View style={[styles[type.name], styles.type]}> <Text style={styles.type_text}>{type.name}</Text> </View>
ããã§
changeText
ã¡ãœããã
changeText
ãããã¯ãããã¹ããã£ãŒã«ãã®ããã¹ããå€æŽããããã³ã«å®è¡ãããŸãã å®éã®ããã¹ãããŒã¿ã¯ãã®ã¡ãœããã«éä¿¡ãããããããŠãŒã¶ãŒãå
¥åããçŸåšã®æ
å ±ãæ ŒçŽããç¶æ
ããããã£ãæŽæ°ããã®ã«é©ããå Žæã§ãã
changeText: function(text){ this.setState({ query: text }); },
search
ã¡ãœããã¯ãããŒã¿ãããã¹ããã£ãŒã«ãã§éä¿¡ããããã³ã«å®è¡ãããŸãã Androidã§ããã¹ããå
¥åãããšã[
å®äº ]ãã¿ã³ã衚瀺ãããã¯ãªãã¯ãããš
onSubmitEditing
ã€ãã³ããããªã¬ãŒãããŸãã
onSubmitEditing
å±æ§ã®å€ãšããŠæ¢ã«å®çŸ©ããŠããŸãã ãã®çµæã次ã®ã¡ãœãããå®è¡ãããŸãã
search: function(){ var pokemon = _.capitalize(this.state.query); this.setState({ isLoading: true }); api(pokemon).then( (data) => { var speech = 'Pokemon was not found. Please type the exact name.'; if(data.doc){ var types = this.state.dataSource.cloneWithRows(data.doc.types); this.setState({ hasResult: true, noResult: false, result: data.doc, types: types, isLoading: false }); var type_names = _.map(data.doc.types, function(type){ return type.name; }); speech = data.doc.name + ". A " + type_names.join(' and ') + ' pokemon. ' + data.doc.description; }else{ this.setState({ hasResult: false, noResult: true, isLoading: false, result: null }); } tts.speak({ text: speech, forceStop : true , language : 'en' }); } ); }
ãã®ã³ãŒããæ±ããŸãã LodashãæäŸãã
capitalize
ã¡ãœããã¯ãæåã®æåãé€ããã¹ãŠã®æåã倧æåã«å€æããããã«åŒã³åºãããŸãã ãã®åŸãç¶æ
ãæŽæ°ããã
isLoading
ããããã£ã
true
ã«èšå®ãã
true
ãããã«ãããæåŸã®ã³ã³ããŒãã³ãã®äžã«ããŒãã£ã³ã°ã€ã³ãžã±ãŒã¿ãŒã衚瀺ãããŸãã
var pokemon = _.capitalize(this.state.query); this.setState({ isLoading: true });
api
ã¢ãžã¥ãŒã«ã䜿çšããŠããããã¯ãŒã¯ãªã¯ãšã¹ããå®è¡ããŸãã
api(pokemon).then( (data) => { ... } );
泚æ ïŒã³ãŒã«ããã¯é¢æ°ã®æ§æã¯ãç§ãã¡ãæ
£ããŠãããã®ãšã¯ãããã«ç°ãªããŸãã
api(pokemon).then(function(data){ ... });
this
ãªããžã§ã¯ãã®å€ãç°ãªããŸãã æ°ããæ§æã«ããã°ããã®ãªããžã§ã¯ãã¯ã³ãŒã«ããã¯é¢æ°ã§ã¯ãªãå€éšã¹ã³ãŒããåç
§ããŸãã ããã«ãããããã䜿çšããŠãçŸåšã®ã¹ã³ãŒããä¿æããå€æ°ãäœæããããšãªããã³ãŒã«ããã¯é¢æ°å
ããç¶æ
ãæŽæ°ã§ããŸãã
ã³ãŒã«ããã¯é¢æ°å
ã§ãããã©ã«ãã®ããã¹ããèšå®ãããé³å£°ã«å€æãããŸãã
var speech = 'Pokemon was not found. Please type the exact name.';
doc
,
cloneWithRows
, ,
dataSource
. ,
dataSource
ListView
.
.
type_names
, , . Lodash
map
. , :
if(data.doc){
, :
hasResult
false
, , .noResult
true
, .isLoading
false
, .result
null
.
... else{ this.setState({ hasResult: false, noResult: true, isLoading: false, result: null }); }
:
if(data.doc){ ... }else{ ... } tts.speak({ text: speech, forceStop : true , language : 'en' });
Pokodex
StyleSheet
API:
var styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#FFF' }, search: { flex: 1 }, result: { flex: 8 }, no_result: { flex: 8, alignItems: 'center' }, loader: { flex: 1, alignItems: 'center' }, main_details: { padding: 30, alignItems: 'center' }, image_dimensions: { width: 100, height: 100 }, main_text: { fontSize: 25, fontWeight: 'bold', textAlign: 'center' }, sub_text: { color: '#6e6e6e' }, description: { marginTop: 20 }, text_input: { height: 40, borderColor: 'gray', borderWidth: 1 }, types: { flexDirection: 'row', marginTop: 20 }, type: { padding: 5, width: 100, alignItems: 'center' }, type_text: { color: '#fff', }, normal: { backgroundColor: '#8a8a59' }, fire: { backgroundColor: '#f08030' }, water: { backgroundColor: '#6890f0' }, electric: { backgroundColor: '#f8d030' }, grass: { backgroundColor: '#78c850' }, ice: { backgroundColor: '#98d8d8' }, fighting: { backgroundColor: '#c03028' }, poison: { backgroundColor: '#a040a0' }, ground: { backgroundColor: '#e0c068' }, flying: { backgroundColor: '#a890f0' }, psychic: { backgroundColor: '#f85888' }, bug: { backgroundColor: '#a8b820' }, rock: { backgroundColor: '#b8a038' }, ghost: { backgroundColor: '#705898' }, dragon: { backgroundColor: '#7038f8' }, dark: { backgroundColor: '#705848' }, steel: { backgroundColor: '#b8b8d0' }, fairy: { backgroundColor: '#e898e8' } });
. ,
flex
1
, Flexbox. , . , . , .
container: { flex: 1, backgroundColor: '#FFF' },
, , :
search: { flex: 1 }, result: { flex: 8 }, no_result: { flex: 8, alignItems: 'center' }, loader: { flex: 1, alignItems: 'center' },
, . , . .
flex: 1
, . 10 , 1 , 8 .
<View style={styles.search}> ... </View> <View style={styles.result}> ... </View> <View style={styles.no_result}> ... </View> <View style={styles.loader}> ... </View>
, ,
main_details
. , , .
main_details: { padding: 30, alignItems: 'center' },
â CSS.
image_dimensions: { width: 100, height: 100 }, main_text: { fontSize: 25, fontWeight: 'bold', textAlign: 'center' }, sub_text: { color: '#6e6e6e' }, description: { marginTop: 20 },
.
ListView
flexDirection
row
. , , (inline effect). . ,
width
. 5 .
alignItems
.
types: { flexDirection: 'row', marginTop: 20 }, type: { padding: 5, width: 100, alignItems: 'center', }, type_text: { color: '#fff', },
. , , .
normal: { backgroundColor: '#8a8a59' }, fire: { backgroundColor: '#f08030' }, water: { backgroundColor: '#6890f0' }, electric: { backgroundColor: '#f8d030' }, grass: { backgroundColor: '#78c850' }, ice: { backgroundColor: '#98d8d8' }, fighting: { backgroundColor: '#c03028' }, poison: { backgroundColor: '#a040a0' }, ground: { backgroundColor: '#e0c068' }, flying: { backgroundColor: '#a890f0' }, psychic: { backgroundColor: '#f85888' }, bug: { backgroundColor: '#a8b820' }, rock: { backgroundColor: '#b8a038' }, ghost: { backgroundColor: '#705898' }, dragon: { backgroundColor: '#7038f8' }, dark: { backgroundColor: '#705848' }, steel: { backgroundColor: '#b8b8d0' }, fairy: { backgroundColor: '#e898e8' }
AppRegistry
. React Native
Pokedex
.
AppRegistry.registerComponent('Pokedex', () => Pokedex);
, -,
react-native run-android
. :

, React, . (,
index.android.js ). React
react-native start
. :
[7:38:33 AM] <START> Building Dependency Graph [7:38:33 AM] <START> Crawling File System [7:38:33 AM] <START> Loading bundles layout [7:38:33 AM] <END> Loading bundles layout (1ms) React packager ready. [7:38:46 AM] <END> Crawling File System (13516ms) [7:38:46 AM] <START> Building in-memory fs for JavaScript [7:38:52 AM] <END> Building in-memory fs for JavaScript (6200ms) [7:38:52 AM] <START> Building in-memory fs for Assets [7:38:59 AM] <END> Building in-memory fs for Assets (6048ms) [7:38:59 AM] <START> Building Haste Map [7:39:03 AM] <START> Building (deprecated) Asset Map [7:39:05 AM] <END> Building (deprecated) Asset Map (2191ms) [7:39:08 AM] <END> Building Haste Map (9348ms) [7:39:08 AM] <END> Building Dependency Graph (35135ms)
Building Dependency Graph adb shell input keyevent 82
. .
Dev settings ,
Debugging IP- , React.

,
Reload JS . , .
React
, Watchman.
Error building DependencyGraph:
Error: Watcher took too long to load
Try running `watchman version` from your terminal
https://facebook.imtqy.com/watchman/docs/troubleshooting.html
at [object Object]._onTimeout (index.js:103:16)
at Timer.listOnTimeout (timers.js:89:15)
:
sudo sysctl fs.inotify.max_user_instances=99999
sudo sysctl fs.inotify.max_user_watches=99999
sudo sysctl fs.inotify.max_queued_events=99999
watchman shutdown-server
, :
echo 999999 | sudo tee -a /proc/sys/fs/inotify/max_user_instances
echo 999999 | sudo tee -a /proc/sys/fs/inotify/max_user_watches
echo 999999 | sudo tee -a /proc/sys/fs/inotify/max_queued_events
watchman shutdown-server
, , . Watchman, .
React , . :
- Android- .
- IP- IP- .
, .
, , Chrome .
Debug in Chrome Enable Live Reload .
console.log Chrome. , .
次ã¯ïŒ
, React Native app?
çµè«ãšããŠ
React Native. : , , . ,
GitHub , .