react-native-elements
Version:
React Native Elements & UI Toolkit
513 lines (481 loc) • 52.7 kB
HTML
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>React Native Web · React Native Elements</title><meta name="viewport" content="width=device-width"/><meta name="generator" content="Docusaurus"/><meta name="description" content="> Comprehensive Guide to create simple app using React Native Web and React Native Elements"/><meta name="docsearch:language" content="en"/><meta property="og:title" content="React Native Web · React Native Elements"/><meta property="og:type" content="website"/><meta property="og:url" content="https://react-native-training.github.io//react-native-elements/blog/2018/12/13/react-native-web.html"/><meta property="og:description" content="> Comprehensive Guide to create simple app using React Native Web and React Native Elements"/><meta name="twitter:card" content="summary"/><link rel="shortcut icon" href="/react-native-elements/img/favicon.png"/><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css"/><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css"/><link rel="alternate" type="application/atom+xml" href="https://react-native-training.github.io//react-native-elements/blog/atom.xml" title="React Native Elements Blog ATOM Feed"/><link rel="alternate" type="application/rss+xml" href="https://react-native-training.github.io//react-native-elements/blog/feed.xml" title="React Native Elements Blog RSS Feed"/><script type="text/javascript" src="https://buttons.github.io/buttons.js"></script><link rel="stylesheet" href="/react-native-elements/css/prism.css"/><link rel="stylesheet" href="/react-native-elements/css/main.css"/><script src="/react-native-elements/js/codetabs.js"></script></head><body class="sideNavVisible separateOnPageNav"><div class="fixedHeaderContainer"><div class="headerWrapper wrapper"><header><a href="/react-native-elements/"><img class="logo" src="/react-native-elements/img/logo.png" alt="React Native Elements"/></a><a href="/react-native-elements/versions.html"><h3>1.0.0</h3></a><div class="navigationWrapper navigationSlider"><nav class="slidingNav"><ul class="nav-site nav-site-internal"><li class=""><a href="/react-native-elements/docs/getting_started.html" target="_self">Docs</a></li><li class=""><a href="/react-native-elements/docs/overview.html" target="_self">Components</a></li><li class=""><a href="/react-native-elements/help.html" target="_self">Help</a></li><li class=""><a href="https://github.com/react-native-training/react-native-elements" target="_self">GitHub</a></li><li class="siteNavGroupActive"><a href="/react-native-elements/blog/" target="_self">Blog</a></li><li class="navSearchWrapper reactNavSearchWrapper"><input type="text" id="search_input_react" placeholder="Search" title="Search"/></li></ul></nav></div></header></div></div><div class="navPusher"><div class="docMainWrapper wrapper"><div class="container docsNavContainer" id="docsNav"><nav class="toc"><div class="toggleNav"><section class="navWrapper wrapper"><div class="navBreadcrumb wrapper"><div class="navToggle" id="navToggler"><i></i></div><h2><i>›</i><span>Recent Posts</span></h2><div class="tocToggler" id="tocToggler"><i class="icon-toc"></i></div></div><div class="navGroups"><div class="navGroup"><h3 class="navGroupCategoryTitle">Recent Posts</h3><ul class=""><li class="navListItem"><a class="navItem" href="/react-native-elements/blog/2019/01/27/1.0-release.html">React Native Elements 1.0</a></li><li class="navListItem navListItemActive"><a class="navItem" href="/react-native-elements/blog/2018/12/13/react-native-web.html">React Native Web</a></li></ul></div></div></section></div><script>
var coll = document.getElementsByClassName('collapsible');
var checkActiveCategory = true;
for (var i = 0; i < coll.length; i++) {
var links = coll[i].nextElementSibling.getElementsByTagName('*');
if (checkActiveCategory){
for (var j = 0; j < links.length; j++) {
if (links[j].classList.contains('navListItemActive')){
coll[i].nextElementSibling.classList.toggle('hide');
coll[i].childNodes[1].classList.toggle('rotate');
checkActiveCategory = false;
break;
}
}
}
coll[i].addEventListener('click', function() {
var arrow = this.childNodes[1];
arrow.classList.toggle('rotate');
var content = this.nextElementSibling;
content.classList.toggle('hide');
});
}
document.addEventListener('DOMContentLoaded', function() {
createToggler('#navToggler', '#docsNav', 'docsSliderActive');
createToggler('#tocToggler', 'body', 'tocActive');
const headings = document.querySelector('.toc-headings');
headings && headings.addEventListener('click', function(event) {
if (event.target.tagName === 'A') {
document.body.classList.remove('tocActive');
}
}, false);
function createToggler(togglerSelector, targetSelector, className) {
var toggler = document.querySelector(togglerSelector);
var target = document.querySelector(targetSelector);
if (!toggler) {
return;
}
toggler.onclick = function(event) {
event.preventDefault();
target.classList.toggle(className);
};
}
});
</script></nav></div><div class="container mainContainer postContainer blogContainer"><div class="wrapper"><div class="lonePost"><div class="post"><header class="postHeader"><h1 class="postHeaderTitle"><a href="/react-native-elements/blog/2018/12/13/react-native-web.html">React Native Web</a></h1><p class="post-meta">December 13, 2018</p><div class="authorBlock"><p class="post-authorName"><a href="https://github.com/haruelrovix" target="_blank" rel="noreferrer noopener">Havit Rovik</a></p></div></header><div><span><blockquote>
<p>Comprehensive Guide to create simple app using React Native Web and React Native Elements</p>
</blockquote>
<p>Case study: <code>gitphone</code>, GitHub repository checker for your smartphone.</p>
<p><img src="https://cdn-images-1.medium.com/max/1000/1*PHcPxP963ascQkeZOqy-rQ.png" /></p>
<h2><a class="anchor" aria-hidden="true" id="toc"></a><a href="#toc" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>ToC</h2>
<ul>
<li>Initialize the project using <a href="https://github.com/VISI-ONE/create-react-native-web-app">CRNWA</a></li>
<li>Make sure everything works: Android, iOS and Web</li>
<li>Add RNE latest ( 1.0.0-beta7 ) to the project</li>
<li>Add 2 screens</li>
</ul>
<p>Screen 1 RNE components:</p>
<ol>
<li>Input</li>
<li>Button with Icon</li>
</ol>
<p>Screen 2 RNE components:</p>
<ol>
<li>Header</li>
<li>ListItem</li>
<li>Avatar</li>
<li>Text</li>
</ol>
<p><code>gitphone</code> should have:</p>
<ul>
<li>routing, <a href="https://reacttraining.com/react-router">react-router</a>. It works great both on Native and Web.</li>
<li>calls to GitHub API. See <a href="https://developer.github.com/v3/">https://developer.github.com/v3/</a>.</li>
</ul>
<h2><a class="anchor" aria-hidden="true" id="0-initial-step"></a><a href="#0-initial-step" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>0️⃣ Initial Step</h2>
<p>Install create-react-native-web-app</p>
<pre><code class="hljs">$ <span class="hljs-string">npm </span>i -g <span class="hljs-built_in">create-react-native-web-app</span>
</code></pre>
<h2><a class="anchor" aria-hidden="true" id="1-first-step"></a><a href="#1-first-step" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>1️⃣ First Step</h2>
<p>Create <code>gitphone</code> project.</p>
<pre><code class="hljs">λ <span class="hljs-keyword">create</span>-react-<span class="hljs-keyword">native</span>-web-app gitphone
⏳ Creating React <span class="hljs-keyword">Native</span> Web App <span class="hljs-keyword">by</span> the <span class="hljs-keyword">name</span> <span class="hljs-keyword">of</span> gitphone ...
✅ Created <span class="hljs-keyword">project</span> folder.
✅ Added <span class="hljs-keyword">project</span> files.
⏳ Installing <span class="hljs-keyword">project</span> dependencies...
yarn <span class="hljs-keyword">install</span> v1<span class="hljs-number">.10</span><span class="hljs-number">.1</span>
[<span class="hljs-number">1</span>/<span class="hljs-number">4</span>] Resolving packages...
[<span class="hljs-number">2</span>/<span class="hljs-number">4</span>] Fetching packages...
info fsevents@<span class="hljs-number">1.2</span><span class="hljs-number">.4</span>: The platform <span class="hljs-string">"win32"</span> <span class="hljs-keyword">is</span> incompatible <span class="hljs-keyword">with</span> this module.
info <span class="hljs-string">"fsevents@1.2.4"</span> <span class="hljs-keyword">is</span> an optional dependency <span class="hljs-keyword">and</span> <span class="hljs-keyword">failed</span> <span class="hljs-keyword">compatibility</span> check. <span class="hljs-keyword">Excluding</span> it <span class="hljs-keyword">from</span> installation.
[<span class="hljs-number">3</span>/<span class="hljs-number">4</span>] Linking dependencies...
[<span class="hljs-number">4</span>/<span class="hljs-number">4</span>] Building <span class="hljs-keyword">fresh</span> packages...
<span class="hljs-keyword">success</span> Saved lockfile.
Done <span class="hljs-keyword">in</span> <span class="hljs-number">797.66</span>s.
✅ Installed <span class="hljs-keyword">project</span> dependencies.
✅ Done! 😁👍 Your <span class="hljs-keyword">project</span> <span class="hljs-keyword">is</span> ready <span class="hljs-keyword">for</span> development.
* <span class="hljs-keyword">change</span> <span class="hljs-keyword">directory</span> <span class="hljs-keyword">to</span> your <span class="hljs-keyword">new</span> <span class="hljs-keyword">project</span>
$ cd gitphone
$ <span class="hljs-keyword">Then</span> run the these commands <span class="hljs-keyword">to</span> <span class="hljs-keyword">get</span> started:
* <span class="hljs-keyword">To</span> run development Web <span class="hljs-keyword">server</span>
$ yarn web
* <span class="hljs-keyword">To</span> run Android <span class="hljs-keyword">on</span> connected device (<span class="hljs-keyword">after</span> installing Android Debug Bridge <span class="hljs-string">"adb"</span> - https://developer.android.com/studio/releases/platform-tools)
$ yarn android
* <span class="hljs-keyword">To</span> run ios simulator (<span class="hljs-keyword">after</span> installing Xcode - <span class="hljs-keyword">only</span> <span class="hljs-keyword">on</span> Apple devices)
$ yarn ios
* <span class="hljs-keyword">To</span> run tests <span class="hljs-keyword">for</span> <span class="hljs-keyword">Native</span> <span class="hljs-keyword">and</span> Web
$ yarn <span class="hljs-keyword">test</span>
* <span class="hljs-keyword">To</span> run <span class="hljs-keyword">build</span> <span class="hljs-keyword">for</span> Web
$ yarn <span class="hljs-keyword">build</span>
</code></pre>
<p>Change to <code>gitphone</code> directory and test the web app by running <code>yarn web</code>.</p>
<pre><code class="hljs">Starting the development server...
Compiled successfully!
You can now view <span class="hljs-keyword">create</span>-react-<span class="hljs-keyword">native</span>-web-app <span class="hljs-keyword">in</span> the browser.
<span class="hljs-keyword">Local</span>: <span class="hljs-keyword">http</span>://localhost:<span class="hljs-number">3001</span>/
<span class="hljs-keyword">On</span> Your Network: <span class="hljs-keyword">http</span>://<span class="hljs-number">172.26</span><span class="hljs-number">.235</span><span class="hljs-number">.145</span>:<span class="hljs-number">3001</span>/
Note that the development <span class="hljs-keyword">build</span> <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> optimized.
<span class="hljs-keyword">To</span> <span class="hljs-keyword">create</span> a production <span class="hljs-keyword">build</span>, <span class="hljs-keyword">use</span> yarn build.
</code></pre>
<p><img src="https://cdn-images-1.medium.com/max/800/1*tmq9VHw3S4cgxfWg8xN3gQ.png" width=300 /></p>
<p>Now, test the <code>gitphone</code> android app by running <code>yarn android</code>.</p>
<pre><code class="hljs">Installing APK <span class="hljs-string">'app-debug.apk'</span> <span class="hljs-keyword">on</span> <span class="hljs-string">'Redmi 4X - 7.1.2'</span> <span class="hljs-keyword">for</span> app:<span class="hljs-keyword">debug</span>
Installed <span class="hljs-keyword">on</span> <span class="hljs-number">1</span> device.
BUILD SUCCESSFUL
Total <span class="hljs-type">time</span>: <span class="hljs-number">21.783</span> secs
Starting: Intent { cmp=com.creaternwapp/.MainActivity }
✨ Done <span class="hljs-keyword">in</span> <span class="hljs-number">25.64</span>s.
</code></pre>
<p>If the build successful, you'll see the app installed on your Android (emulator) device.</p>
<p><img src="https://cdn-images-1.medium.com/max/800/1*BddouTisdXvDzY5vB9U3pQ.png" width=300 /></p>
<p>But if you got an error when run <code>yarn android</code>, please see Troubleshooting section below.</p>
<p>The last part for First Step, make sure it can be run on iOS without any problem. Run <code>yarn ios</code> and <em>voila!</em></p>
<p><img src="https://cdn-images-1.medium.com/max/800/1*6AHlumHN29RANlXsrXDu4g.png" width=300 /></p>
<h2><a class="anchor" aria-hidden="true" id="2-step-two"></a><a href="#2-step-two" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>2️⃣ Step Two</h2>
<p>Installing React Native Elements (RNE).</p>
<pre><code class="hljs">$ yarn add react-<span class="hljs-keyword">native</span>-elements<span class="hljs-meta">@beta</span>
</code></pre>
<p>Installing React Native Vector Icons (RNVI).</p>
<pre><code class="hljs">$ yarn <span class="hljs-keyword">add</span><span class="bash"> react-native-vector-icons
</span></code></pre>
<p>Linking:</p>
<pre><code class="hljs">$ react-<span class="hljs-keyword">native</span> link react-<span class="hljs-keyword">native</span>-vector-icons
</code></pre>
<p>Both RNE and RNVI are written using es6. If you run <code>yarn web</code> at this point, you'll got an error.</p>
<pre><code class="hljs">./node_modules/react-native-elements/src/config/withTheme.js
Module <span class="hljs-keyword">parse</span> failed: Unexpected <span class="hljs-keyword">token</span> (12:28)
You may need <span class="hljs-keyword">an</span> appropriate loader to handle this <span class="hljs-keyword">file</span> <span class="hljs-keyword">type</span>.
</code></pre>
<p>We need to tell webpack to transpile them.</p>
<ol>
<li>Open <code>config/webpack.config.dev.js</code></li>
<li>On line 141 <code>Process JS with babel</code>, add RNE and RNVI to include</li>
<li>Do the same for <code>config/webpack.config.prod.js</code> as well 👌</li>
</ol>
<p>If you get lost, see this <a href="https://gist.github.com/haruelrovix/01d335dfcabec17a6aa5bc7a53fef277">gist</a> or commit <a href="https://github.com/haruelrovix/gitphone/commit/8c0e6036d9231cc934285502528a2061b848ce2d">8c0e603</a>.</p>
<h2><a class="anchor" aria-hidden="true" id="3-give-it-a-try"></a><a href="#3-give-it-a-try" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>3️⃣ Give it a try</h2>
<p>Now, let's grasp the idea how RNE works.</p>
<ol>
<li><p>Open src/App.js</p></li>
<li><p>Import Button from RNE</p>
<pre><code class="hljs"><span class="hljs-keyword">import</span> { Button } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native-elements'</span>;
</code></pre></li>
<li><p>On render, change TouchableHighlight to use RNE's Button</p></li>
<li><p>Run yarn ios, yarn android and yarn web to see it in action! 👏</p></li>
</ol>
<p>Note: If you got an error <code>Could not find com.android.tools.build.appt2</code> when running <code>yarn android</code>, add <code>google</code> on the gradle repositories.</p>
<p>See this <a href="https://gist.github.com/haruelrovix/51a695a4fe292767bedc32ec638f9736">gist</a> or commit for the details: <a href="https://github.com/haruelrovix/gitphone/commit/a2ebba14aef533925b593933fa885e2f990b2ace">a2ebba1</a>.</p>
<h2><a class="anchor" aria-hidden="true" id="4-add-home-component"></a><a href="#4-add-home-component" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>4️⃣ Add Home component</h2>
<p>Our first component will be <code>Home</code>. On this component, there are two input fields and one Submit button.</p>
<ol>
<li>Inside <code>src</code>, create new folder: <code>Components</code></li>
<li>Add new file called <code>Home.js</code> <a href="https://gist.github.com/haruelrovix/04eeb6c4d8d0cc56e041e5be2c20bc97">gist</a></li>
<li>On <code>App.js</code>, import <code>Home</code> component <a href="https://gist.github.com/haruelrovix/15cd4badc3a9ec949037b19d9195d6bc">gist</a></li>
<li>Run <code>yarn ios</code>, <code>yarn android</code> and <code>yarn web</code> to see it in action! 🎇</li>
</ol>
<h3><a class="anchor" aria-hidden="true" id="styling-for-home-component"></a><a href="#styling-for-home-component" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Styling for Home component</h3>
<p>You should notice that our <code>Home</code> doesn’t look good in term of UI. Let’s add styling for it.</p>
<ol>
<li>Inside <code>Components</code>, create <code>Shared.style.js</code> file <a href="https://gist.github.com/haruelrovix/7fee3c03b9fead9b74739e28a24effa9">gist</a></li>
<li>Import the style and update <code>Home</code> component as below <a href="https://gist.github.com/haruelrovix/4fb2e695d1562ff3475ebc91e6c27fcd">gist</a></li>
<li>Looks better now*, commit for adding Home component: <a href="https://github.com/haruelrovix/gitphone/commit/2e510c462c68d7c68433f2706cf8fbb847d6541e">2e510c4</a>.</li>
</ol>
<p><em>Wait a minute…</em> *Seems there is a problem with RNVI on the web version. You can check this <a href="https://github.com/oblador/react-native-vector-icons#web-with-webpack">Web (with webpack)</a> article or just following steps bellow.</p>
<ol>
<li>Open <code>config/webpack.config.dev.js</code></li>
<li>Add url-loader on line 162 <a href="https://gist.github.com/haruelrovix/edd520f4bf4268e17ef56f40314080a5">gist</a></li>
<li>Do the same for <code>config/webpack.config.prod.js</code> as well 👌</li>
<li>Open <code>src/index.js</code> file</li>
<li>Add <code>iconFont</code> and append <code>style</code> to document’s head <a href="https://gist.github.com/haruelrovix/b291e8a4f34577d94e85570d304b82fe">gist</a></li>
</ol>
<p><img src="https://cdn-images-1.medium.com/max/2584/1*YS7jioDKIKKvort5AzGXYA.png" alt="Our RNE x RNW progress so far~"><em>Our RNE x RNW progress so far~</em></p>
<h2><a class="anchor" aria-hidden="true" id="5-routing"></a><a href="#5-routing" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>5️⃣ Routing</h2>
<p>Next, let’s add second component: <code>CommitList</code>.</p>
<ol>
<li>Create new folder inside <code>Components</code> named <code>Commit</code></li>
<li>Add new file: <code>CommitList.js</code> <a href="https://gist.github.com/haruelrovix/4cece6275cf40d97defb036756bab82b">gist</a></li>
</ol>
<p>On our app, user goes to second screen by click on <code>Submit</code> button. How do we implement it?</p>
<p><em>“react-router comes to the rescue”</em> - <a href="https://reacttraining.com/react-router/">https://reacttraining.com/react-router/</a></p>
<p>Add react-router-dom and react-router-native</p>
<pre><code class="hljs">$ yarn add react-router-dom react-router-native
</code></pre>
<p>Web needs <code>BrowserRouter</code> while native <code>NativeRouter</code>. We need to separate it based on the platform.</p>
<ol>
<li>On <code>src</code>, create <code>Utils</code> folder</li>
<li>Add two files on <code>Utils</code>: <code>Routing.native.js</code> and <code>Routing.web.js</code> <a href="https://gist.github.com/haruelrovix/3d7e26df6bb2d6056e2f4612a77fd2fc">gist</a></li>
</ol>
<p>Those file’s content differ only on the second line. <a href="https://gist.github.com/haruelrovix/32353543e417373a770365f855701c37">gist</a></p>
<p>Now, glue it together.</p>
<ol>
<li><p>Open <code>App.js</code>, import <code>CommitList</code> component</p></li>
<li><p>Import <code>Route</code>, <code>Router</code> and <code>Switch</code> from <code>Utils/Routing</code></p></li>
<li><p>Implement routing inside <code>render</code> method <a href="https://gist.github.com/haruelrovix/d5bf357efbbf094b26549f40709ec74f">gist</a></p></li>
<li><p>Now for the action on <code>Submit</code> button, open <code>Home.js</code></p></li>
<li><p>Import <code>withRouter</code> from <code>Utils/Routing</code></p>
<pre><code class="hljs"><span class="hljs-keyword">import</span> { withRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'../Utils/Routing'</span>;
</code></pre></li>
<li><p><code>WithRouter</code> is an HOC. Use it to wrap <code>Home</code> component</p>
<pre><code class="hljs"><span class="hljs-builtin-name">export</span><span class="hljs-built_in"> default </span>withRouter(Home);
</code></pre></li>
<li><p>Add <code>onPress</code> property for the button</p>
<pre><code class="hljs"><span class="hljs-attr">onPress</span>={this.<span class="hljs-literal">on</span>PressButton}
</code></pre></li>
<li><p>Implement the <code>onPressButton</code> event handler</p>
<pre><code class="hljs"><span class="hljs-function"><span class="hljs-title">onPressButton</span> = <span class="hljs-params">()</span> =></span> <span class="hljs-keyword">this</span>.props.history.push(<span class="hljs-string">'/commit'</span>);
</code></pre></li>
<li><p>All <code>Home</code> together <a href="https://gist.github.com/haruelrovix/8fc8ae9dab580c5e79f24a59a2c195b6">gist</a> | <a href="https://github.com/haruelrovix/gitphone/commit/f193aa3c268e7be263ae529de0f719ffd443e26d">commit</a></p></li>
</ol>
<p>Test it on <code>web</code> and <code>android</code>, you should be able to go back and forth between screens using <code>Submit</code> and pressing <code>Back</code> button.</p>
<p><em>“How can I go back on iOS?”</em> 😂</p>
<h3><a class="anchor" aria-hidden="true" id="implement-withheader"></a><a href="#implement-withheader" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Implement withHeader</h3>
<p>We will create a <code>withHeader</code> HOC. Why HOC? We can reuse it easier <em>if we add more screens later.</em></p>
<ol>
<li><p>On <code>src</code>, create <code>HOCs</code> folder</p></li>
<li><p>Add <code>withHeader.js</code> file</p></li>
<li><p>Import <code>Header</code> from RNE and <code>Icon</code> from <code>RNVI/FontAwesome</code></p>
<pre><code class="hljs"><span class="hljs-keyword">import</span> { <span class="hljs-keyword">Header</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native-elements'</span>;
<span class="hljs-keyword">import</span> Icon <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native-vector-icons/FontAwesome'</span>;
</code></pre></li>
<li><p><code>withHeader</code> accepts one prop: <code>title</code></p>
<pre><code class="hljs">const withHeader = <span class="hljs-function"><span class="hljs-params">({ title = <span class="hljs-string">''</span> })</span> =></span> (WrappedComponent) => {
</code></pre></li>
<li><p>Event handler to go back / go home</p>
<pre><code class="hljs"><span class="hljs-function"><span class="hljs-title">goBack</span> = <span class="hljs-params">()</span> =></span> <span class="hljs-keyword">this</span>.props.history.goBack();
<span class="hljs-function">
<span class="hljs-title">goHome</span> = <span class="hljs-params">()</span> =></span> <span class="hljs-keyword">this</span>.props.history.replace(<span class="hljs-string">'/'</span>);
</code></pre></li>
<li><p>Import and use <code>withHeader</code> in <code>CommitList</code> component <a href="https://gist.github.com/haruelrovix/b1608f9f010caa47c18ebc71d87106ae">gist</a> | <a href="https://github.com/haruelrovix/gitphone/commit/0cf995bde91f5958e252188f1343de923069e7f3">commit</a></p></li>
</ol>
<h2><a class="anchor" aria-hidden="true" id="6-fetch-data-from-github-api"></a><a href="#6-fetch-data-from-github-api" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>6️⃣ Fetch data from GitHub API</h2>
<p>Let’s fetch a real-live data: list commit on repository by <a href="https://developer.github.com/v3/repos/commits/#list-commits-on-a-repository">GitHub</a> and render it on our second screen, <code>CommitList</code>.</p>
<pre><code class="hljs">GET /repos/:owner/:repo/commits
</code></pre>
<p>Ideally, the :owner and :repo are form values from our first screen. Since the objective of this article is RNE x RNW, talk about that form (and state-management) later on.</p>
<p>To fetch GitHub API, we will use <a href="https://github.com/esphen/fetch-hoc">fetch-hoc</a> package and also need <a href="https://redux.js.org/api/compose">compose</a> from <code>redux</code>, to handle multiple HOCs on the same component.</p>
<pre><code class="hljs">$ yarn add fetch-hoc redux
</code></pre>
<ol>
<li><p>Open <code>CommitList.js</code></p></li>
<li><p>Import <code>{ compose }</code> from <code>redux</code> and <code>fetch</code> from <code>fetch-hoc</code></p></li>
<li><p>Use it as below <a href="https://gist.github.com/haruelrovix/1c3affbfd585c3b8acfc1c156164fd1f">gist</a> | <a href="https://github.com/haruelrovix/gitphone/commit/334197c7c05bd1bdb1b648ca56cfe69c8b496eed">commit</a></p></li>
</ol>
<p>Now run <code>yarn web</code>, open <code>network</code> tab of <code>DevTools</code> and click <code>Submit</code> button, you’ll see bunch of commit data. By default GitHub API returning 30 commits.</p>
<h3><a class="anchor" aria-hidden="true" id="render-commit-data"></a><a href="#render-commit-data" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Render commit data</h3>
<p>Commit data that will be displayed on the screen:</p>
<pre><code class="hljs">author.avatar_url
commit:
author.name
message
</code></pre>
<p>Let’s modify <code>CommitList.js</code></p>
<ol>
<li><p>Add new imports</p>
<pre><code class="hljs"><span class="hljs-keyword">import</span> { ActivityIndicator, Dimensions, FlatList, Platform, <span class="hljs-keyword">View</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native'</span>;
<span class="hljs-keyword">import</span> { Avatar, ListItem } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native-elements'</span>;
</code></pre></li>
<li><p>On main render, modify it as below</p>
<pre><code class="hljs"><span class="xml"><span class="hljs-tag"><<span class="hljs-name">View</span> <span class="hljs-attr">style</span>=</span></span><span class="hljs-template-variable">{styles.container}</span><span class="xml"><span class="hljs-tag">></span>
</span><span class="hljs-template-variable">{this.renderContent()}</span><span class="xml">
<span class="hljs-tag"></<span class="hljs-name">View</span>></span>
</span></code></pre></li>
<li><p>Create <code>renderContent</code> method</p>
<pre><code class="hljs">renderContent = () => (
<span class="hljs-keyword">this</span>.props.loading ?
<ActivityIndicator color=<span class="hljs-string">'#87ceeb'</span> /> :
<FlatList
keyExtractor={<span class="hljs-keyword">this</span>.keyExtractor}
<span class="hljs-keyword">data</span>={<span class="hljs-keyword">this</span>.props.<span class="hljs-keyword">data</span>}
renderItem={<span class="hljs-keyword">this</span>.renderItem}
/>
)
</code></pre></li>
<li><p>Create <code>renderItem</code> method</p>
<pre><code class="hljs">renderItem = ({ item }) => (
<ListItem
title={item<span class="hljs-selector-class">.commit</span><span class="hljs-selector-class">.author</span><span class="hljs-selector-class">.name</span>}
subtitle={item<span class="hljs-selector-class">.commit</span><span class="hljs-selector-class">.message</span>}
leftElement={this.renderLeftElement(item)
/>
)
</code></pre></li>
<li><p>Create <code>renderLeftElement</code> method</p>
<pre><code class="hljs">renderLeftElement = <span class="hljs-function">(<span class="hljs-params">item</span>) =></span> (
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">View</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Avatar</span>
<span class="hljs-attr">source</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">uri:</span> <span class="hljs-attr">item.author.avatar_url</span> }}
<span class="hljs-attr">size</span>=<span class="hljs-string">'medium'</span>
<span class="hljs-attr">rounded</span>
/></span>
<span class="hljs-tag"></<span class="hljs-name">View</span>></span>
)
</span></code></pre></li>
<li><p>Here is our new <code>CommitList</code> including the styling to make it prettier <a href="https://gist.github.com/haruelrovix/e4b02328766efd1491338d5111becff7">gist</a> | <a href="https://github.com/haruelrovix/gitphone/commit/27a78672958f0caaa34b3e93c934685b9dcebd50">commit</a></p></li>
</ol>
<p><strong>Here they are!</strong></p>
<p><img src="https://cdn-images-1.medium.com/max/6436/1*iD3lSG6D3lGDkJr5HB2i2A.png" alt="awesome, eh?"><em>awesome, eh?</em></p>
<h2><a class="anchor" aria-hidden="true" id="7-handle-form-submission"></a><a href="#7-handle-form-submission" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>7️⃣ Handle form submission</h2>
<p>Our app looks great so far. But we are not passing values from first to second screen. Let’s do it.</p>
<ol>
<li><p>To handle form, we’ll use <a href="https://github.com/jaredpalmer/formik">formik</a></p>
<pre><code class="hljs">$ yarn <span class="hljs-keyword">add</span><span class="bash"> formik
</span></code></pre></li>
<li><p>Open <code>Home.js</code> and import it</p>
<pre><code class="hljs"><span class="hljs-keyword">import</span> { Formik } <span class="hljs-keyword">from</span> <span class="hljs-string">'formik'</span>;
</code></pre></li>
<li><p>Wrap main <code>View</code> with <code>formik</code></p>
<pre><code class="hljs"><Formik initialValues={{ owner: <span class="hljs-string">''</span>, repo: <span class="hljs-string">''</span> }}
onSubmit={this.onPressButton}>
{({ handleChange, handleSubmit, values }) => (
<View style={styles.container}>
</code></pre></li>
<li><p>Add <code>onChangeText</code> handler to the <code>Input</code></p>
<pre><code class="hljs"><Input ... onChangeText={handleChange(<span class="hljs-string">'owner'</span>)} <span class="hljs-keyword">value</span>={values.owner}
<Input ... onChangeText={handleChange(<span class="hljs-string">'repo'</span>)} <span class="hljs-keyword">value</span>={values.repo}
</code></pre></li>
<li><p>Change <code>Button</code> <code>onPress</code> props to <code>handleSubmit</code></p>
<pre><code class="hljs"><<span class="hljs-keyword">Button</span> ... onPress={handleSubmit}
</code></pre></li>
<li><p>Don’t forget to close the main <code>View</code></p>
<pre><code class="hljs"> <span class="hljs-tag"></<span class="hljs-name">View</span>></span>
)}
<span class="hljs-tag"></<span class="hljs-name">Formik</span>></span>
</code></pre></li>
</ol>
<p>Form submission: done 👌 Next question: How do we pass these values to second screen? <em>Send them when we redirect to second screen!</em></p>
<ol>
<li><p>Inside <code>onPressButton</code> method, send an object instead of <code>pathname</code> only.</p>
<pre><code class="hljs"><span class="hljs-selector-tag">this</span><span class="hljs-selector-class">.props</span><span class="hljs-selector-class">.history</span><span class="hljs-selector-class">.push</span>({
<span class="hljs-attribute">pathname</span>: <span class="hljs-string">'/commit'</span>,
state: { owner, repo }
});
</code></pre></li>
<li><p>Open <code>CommitList</code>, import <code>withRouter</code></p>
<pre><code class="hljs"><span class="hljs-keyword">import</span> { withRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../Utils/Routing'</span>;
</code></pre></li>
<li><p>Add <code>withRouter</code> inside <code>compose</code></p></li>
<li><p>Get the values passed down to <code>withRouter</code> and use it to <code>fetch</code></p>
<pre><code class="hljs">withHeader({ title: 'Commits' }),
withRouter,
fetch(({ location: { <span class="hljs-keyword">state</span> = {} } }) => (
`https://api.github.com/repos/${<span class="hljs-keyword">state</span>.owner}/${<span class="hljs-keyword">state</span>.repo}/commits`
))
</code></pre></li>
</ol>
<p>HOC’s order does matter. So, make sure it the same as snippet above. In case you lost, here is the commit: <a href="https://github.com/haruelrovix/gitphone/commit/1d83c5e1487d2d99c00cc1b18f563ed4497d87b9">1d83c5e</a>.</p>
<p>Test the app. Now we should able to fetch any GitHub repository, <em>with some caveats.</em> 👀</p>
<h2><a class="anchor" aria-hidden="true" id="8-polishing-the-app"></a><a href="#8-polishing-the-app" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>8️⃣ Polishing the app</h2>
<p>What happens if we fetch repository which doesn’t exist? <em>Red screen on native, blank screen on web!</em> 😹</p>
<p><code>fetch-hoc</code> returns an error if it has. Let’s use it.</p>
<ol>
<li><p>On <code>CommitList</code>, modify <code>renderContent</code></p>
<pre><code class="hljs"><span class="hljs-keyword">this</span>.props.loading ?
<ActivityIndicator color=<span class="hljs-string">'#87ceeb'</span> /> :
<span class="hljs-keyword">this</span>.renderFlatList()
</code></pre></li>
<li><p>Import <code>Text</code> from RNE</p>
<pre><code class="hljs"><span class="hljs-keyword">import</span> { ..., Text } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-native-elements'</span>;
</code></pre></li>
<li><p>Add <code>renderFlatList</code> method</p>
<pre><code class="hljs"><span class="hljs-keyword">this</span>.props.error ?
<Text h4>Error: {<span class="hljs-keyword">this</span>.props.<span class="hljs-keyword">data</span>.message || <span class="hljs-string">'😕'</span>}</Text> :
<FlatList ... />
</code></pre></li>
</ol>
<p>Test it. Instead of <em>red or blank</em> screen, now <code>Error: Not Found</code> displayed.</p>
<p>What’s else? Try to fetch <code>facebook/react-native</code>. We got another error 🙀</p>
<pre><code class="hljs">Cannot read property 'avatar_url' of null
</code></pre>
<p>Not all of <code>author</code> have <code>avatar_url</code>. We should do this for the Avatar <code>source</code>.</p>
<pre><code class="hljs">source={{uri: (item.author && item.author.avatar_url) || undefined}}
</code></pre>
<p>So, our app renders nothing if it has no url? It doesn’t look good. <em>Solution: render author initial name.</em></p>
<p>With the help of RegEx and Avatar <code>title</code> props, <code>renderLeftElement</code> should look like this now:</p>
<pre><code class="hljs">renderLeftElement = (item) => {
const initials = item.commit.author.name.match(/\b\w/g) || [];
return (
<View style={leftElementStyle}>
<Avatar
title={((initials.shift() || '') + (initials.pop() || ''))}
...
</code></pre>
<p>Commit for Polishing the app section: <a href="https://github.com/haruelrovix/gitphone/commit/943974b285635884dc3ec1d7981146307dfd98d3">943974b</a>.</p>
<p>When I wrote this, fetch <code>facebook/react-native</code> returning following:</p>
<p><img src="https://cdn-images-1.medium.com/max/3812/1*OYTvJP0RLLQemyT0ukb1Iw.png" alt="Why no love for regex? Thanks to [Sanoor](https://stackoverflow.com/a/33076482)."><em>Why no love for regex? Thanks to <a href="https://stackoverflow.com/a/33076482">Sanoor</a>.</em></p>
<h2><a class="anchor" aria-hidden="true" id="conclusion"></a><a href="#conclusion" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Conclusion</h2>
<p>We have created a simple app using RNE + RNW 👏</p>
<ul>
<li><p>Works great on iOS, web and android? ✅</p></li>
<li><p>Use components from react-native-elements? ✅</p></li>
<li><p>Move between screens? ✅</p></li>
<li><p>API calls? ✅</p></li>
</ul>
<p>Some improvements for <code>gitphone</code>:</p>
<p>If you go back from <code>Commits</code> screen, input form on <code>Home</code> screen are empty. If you want preserve previous values, this can be fixed easily by introducing redux to the app. References here: <a href="https://github.com/haruelrovix/rnw-github/pull/1/commits/48108ddc3e80669b9d57b2f998a5073d5e5eabb0">48108dd</a>.</p>
<p>Can we fetch more commits data once we reach the most bottom of the list? Infinite scroll?</p>
<p>For web, we can use <a href="https://github.com/joshwnj/react-visibility-sensor">react-visibility-sensor</a>. Check it out: <a href="https://github.com/haruelrovix/rnw-github/pull/1/commits/6c1f6894d78840648a11bbdf2d0e841fb6dad12d">6c1f689</a>.</p>
<p>For native, it’s easier. We can use <code>FlatList</code> <code>onEndReached</code> props. To give you an idea how, see this: <a href="https://github.com/haruelrovix/rnw-github/pull/2/commits/9d2e1f2a3e8605f8184f1f8950eb0175045bb67a">9d2e1f2</a>.</p>
<h2><a class="anchor" aria-hidden="true" id="troubleshooting"></a><a href="#troubleshooting" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Troubleshooting 💺</h2>
<p><strong>#1</strong> <strong>Build failed when running <code>yarn android</code></strong></p>
<pre><code class="hljs">:app:compileDebugAidl FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:compileDebugAidl'.
> java.lang.IllegalStateException: aidl is missing
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
</code></pre>
<p>Here is how to fix #1:</p>
<ol>
<li>Open Android Studio.</li>
</ol>
<p><img src="https://cdn-images-1.medium.com/max/2000/1*GJ4GJ5KKimpr7MZP4R2yPA.png" alt=""></p>
<ol start="2">
<li>Open <code>android</code> project under <code>gitphone</code>.</li>
</ol>
<p><img src="https://cdn-images-1.medium.com/max/2000/1*jyLo3Jk-nudieT3aaEzUBQ.png" alt=""></p>
<ol start="3">
<li>Click Update on this prompt.</li>
</ol>
<p><img src="https://cdn-images-1.medium.com/max/2000/1*7I2tqGZ9C63aUGOtae-XHg.png" alt=""></p>
<p>Wait for Android Studio syncing the project.</p>
<ol start="4">
<li>It synced successfully with two errors.</li>
</ol>
<p><img src="https://cdn-images-1.medium.com/max/2558/1*GUlICoUm4cU4KzUfps3W0Q.png" alt=""></p>
<ol start="5">
<li><p>At this stage, just click <code>Update Build Tools version and sync project</code> on the sync window.</p></li>
<li><p>Now, the remaining warning is the <code>Configuration 'compile'...</code></p></li>
<li><p>To fix that, open <code>app/build.gradle</code> file, change <code>dependencies</code> section (line 139) to use <code>implementation</code> instead of <code>compile</code>.</p>
<p>dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.android.support:appcompat-v7:23.0.1"
implementation "com.facebook.react:react-native:+"
}</p></li>
<li><p>Sync it again and close Android Studio.</p></li>
</ol>
<p><img src="https://cdn-images-1.medium.com/max/2000/1*lIP2u1_7NmTmy8mcri6Smw.png" alt=""></p>
<p>Troubleshooting for android is done. Now, you should be able to run <code>yarn android</code> successfully.</p>
<p><strong>#2 Build failed when running <code>yarn ios</code></strong></p>
<pre><code class="hljs">** BUILD FAILED **
The following build commands failed:
CompileC /gitphone/ios/build/Build/Intermediates.noindex/React.build/Debug-iphonesimulator/double-conversion.build/Objects-normal/x86_64/strtod.o /gitphone/node_modules/react-native/third-party/double-conversion-1.1.5/src/strtod.cc normal x86_64 c++ com.apple.compilers.llvm.clang.1_0.compiler
</code></pre>
<p>Here is how to fix #2:</p>
<p>Inside the project, run script below from your favourite terminal</p>
<pre><code class="hljs">$ curl -L https://git.io/fix-rn-xcode10 | bash
</code></pre>
<p>If you run <code>yarn ios</code> again, and you got this error</p>
<pre><code class="hljs">The following build commands failed:
Libtool /gitphone/ios/build/Build/Products/Debug-iphonesimulator/libRCTWebSocket.a normal x86_64
(1 failure)
</code></pre>
<p>Please run this script:</p>
<pre><code class="hljs">$ cp ios/build/Build/Products/Debug-iphonesimulator/libfishhook.a node_modules/react-native/Libraries/WebSocket
</code></pre>
<p>Troubleshooting for iOS is done. Now, you should be able to run <code>yarn ios</code> successfully.</p>
<h3><a class="anchor" aria-hidden="true" id="authors"></a><a href="#authors" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Authors</h3>
<ul>
<li><a href="https://github.com/haruelrovix">haruelrovix</a></li>
<li><a href="https://github.com/andangrd">andangrd</a></li>
</ul>
</span></div></div><div class="blogSocialSection"></div></div><div class="blog-recent"><a class="button" href="/react-native-elements/blog">Recent Posts</a></div></div></div><nav class="onPageNav"><ul class="toc-headings"><li><a href="#toc">ToC</a></li><li><a href="#0-initial-step">0️⃣ Initial Step</a></li><li><a href="#1-first-step">1️⃣ First Step</a></li><li><a href="#2-step-two">2️⃣ Step Two</a></li><li><a href="#3-give-it-a-try">3️⃣ Give it a try</a></li><li><a href="#4-add-home-component">4️⃣ Add Home component</a><ul class="toc-headings"><li><a href="#styling-for-home-component">Styling for Home component</a></li></ul></li><li><a href="#5-routing">5️⃣ Routing</a><ul class="toc-headings"><li><a href="#implement-withheader">Implement withHeader</a></li></ul></li><li><a href="#6-fetch-data-from-github-api">6️⃣ Fetch data from GitHub API</a><ul class="toc-headings"><li><a href="#render-commit-data">Render commit data</a></li></ul></li><li><a href="#7-handle-form-submission">7️⃣ Handle form submission</a></li><li><a href="