<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[The React Native Log - Medium]]></title>
        <description><![CDATA[All things React Native — tutorials, experiments, tips &amp; tricks, snippets - Medium]]></description>
        <link>https://medium.com/the-react-native-log?source=rss----deee1de989f---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>The React Native Log - Medium</title>
            <link>https://medium.com/the-react-native-log?source=rss----deee1de989f---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 03:35:59 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/the-react-native-log" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[How to Reset React Native Cache — NPM, iOS, Android, and More]]></title>
            <link>https://medium.com/the-react-native-log/how-to-reset-react-native-cache-npm-ios-android-and-more-1487182b39e4?source=rss----deee1de989f---4</link>
            <guid isPermaLink="false">https://medium.com/p/1487182b39e4</guid>
            <category><![CDATA[debugging]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[react-native]]></category>
            <dc:creator><![CDATA[Spencer Carli]]></dc:creator>
            <pubDate>Wed, 02 Jun 2021 21:27:46 GMT</pubDate>
            <atom:updated>2021-06-02T21:27:46.301Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f8Tbg2XNbYuVh3rPQwa_4g.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@sigmund">@sigmund</a>.</figcaption></figure><h3>How to Reset React Native Cache — NPM, iOS, Android, and More</h3><p>Things can get… funky in React Native. Here’s how to start fresh and reset a React Native app cache.</p><p>There are a lot of things in play in a React Native app including:</p><ul><li>NPM/Yarn</li><li>Cocoapods</li><li>Watchman</li><li>Metro bundler</li><li>React Native</li><li>iOS Build</li><li>Android Build</li></ul><p>When things start to get weird/unexpected what do you do? Track down how to clear each one of those folders? Just clear one out?</p><p>Here’s the easiest method…</p><h3>How to Use React Native Clean Project to Clear Your React Native App</h3><p><a href="https://github.com/pmadruga/react-native-clean-project">React Native Clean Project</a> is a CLI plugin that will clear out all the things that could be causing you grief with your React Native app.</p><p>First, install the package as a development dependency:</p><pre>yarn add react-native-clean-project --dev</pre><p>or</p><pre>npm install --save-dev react-native-clean-project</pre><p>Then you’ll want to set up some scripts in your package.json. You&#39;ve got two options here - interactive or auto.</p><pre>// package.json<br><br>{<br>  &quot;scripts&quot;: {<br>    &quot;clean&quot;: &quot;react-native clean-project&quot;,<br>    &quot;clean:auto&quot;: &quot;react-native clean-project-auto&quot;<br>  }<br>}</pre><p>You can then run those via your command line</p><pre>yarn clean OR npm run clean <br>yarn clean:auto OR npm run clean:auto</pre><h3>Why Interactive?</h3><p>Interactive is going to let you choose what you clear from the cache. If you suspect it’s one thing, or it’s only affecting one platform, you can just focus there.</p><p><strong>Benefit:</strong> Faster build times because you don’t need to reinstall and rebuild all the caches.</p><p><strong>Drawback:</strong> You have to monitor it and make decisions.</p><h3>Why Auto?</h3><p>Auto mode is going to use the <a href="https://github.com/pmadruga/react-native-clean-project#content">CLI defaults</a> to get the app back to a “freshly-cloned, never-started repo”.</p><p><strong>Benefit:</strong> Run it and forget it. No decisions or monitoring required.</p><p><strong>Drawback:</strong> Slower initial rebuild time because you have to rebuild every cache.</p><h3>Why is this necessary? Why does this happen?</h3><p>Like I said before, there are a lot of moving parts in a React Native app.</p><p>We’re working with a multiple ecosystems (NPM, Cocoapods), multiple platforms (iOS, Android, Web), and multiple tools (React Native, Metro, Homebrew). 💩 happens and sometimes we need to clean it up.</p><p><em>Originally published at </em><a href="https://www.reactnativeschool.com/how-to-reset-react-native-cache-npm-ios-android-and-more/"><em>https://www.reactnativeschool.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1487182b39e4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-react-native-log/how-to-reset-react-native-cache-npm-ios-android-and-more-1487182b39e4">How to Reset React Native Cache — NPM, iOS, Android, and More</a> was originally published in <a href="https://medium.com/the-react-native-log">The React Native Log</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Get Started with React Query — Migrate from Fetch]]></title>
            <link>https://medium.com/the-react-native-log/how-to-get-started-with-react-query-migrate-from-fetch-18fb426c3760?source=rss----deee1de989f---4</link>
            <guid isPermaLink="false">https://medium.com/p/18fb426c3760</guid>
            <category><![CDATA[mobile-development]]></category>
            <category><![CDATA[react-query]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[api]]></category>
            <dc:creator><![CDATA[Spencer Carli]]></dc:creator>
            <pubDate>Thu, 20 May 2021 13:51:49 GMT</pubDate>
            <atom:updated>2021-05-20T13:51:49.149Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5jUcVltzU3eZTaGiIdSFPg.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@7bbbailey">Barth Bailey</a>.</figcaption></figure><h3>How to Get Started with React Query — Migrate from Fetch</h3><p>Fetching data from a remote source is a must in just about every app you’re going to build. Unfortunately, fetching data is rarely as simple as just fetching the data and rendering it. A few things to consider:</p><ul><li>What do we do when we’re waiting for the data to load?</li><li>What if an error occurs?</li><li>How do I keep my data up to data?</li><li>What if my user has a poor/slow internet connection?</li></ul><blockquote>This post was originally published on <a href="https://www.reactnativeschool.com/how-to-get-started-with-react-query-migrate-from-fetch">React Native School</a>! If you’re interested in hundreds of React Native tutorials and courses be sure to check it out!</blockquote><p>These are all things that <a href="https://react-query.tanstack.com/">React Query</a> can help you with.</p><p>Today we’ll be migrating a basic demo app from using the fetch API to using React Query.</p><p>The final code can be <a href="https://github.com/ReactNativeSchool/react-query-intro">viewed on Github</a>.</p><h3>App Overview</h3><p>Let’s take a look at our app. We can request a list of posts and then display them. When tapping on a post title we navigate to a new screen where we can also see the comments, which come from a separate request.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/650/0*u99whll8eqjFByj2.png" /></figure><p>Right now that data is fetched via the fetch API.</p><pre>// App/screens/List.js<br><br>import React from &#39;react&#39;;<br>import { View, StyleSheet, FlatList, TouchableOpacity } from &#39;react-native&#39;;<br><br>import { Text } from &#39;../components/Text&#39;;<br>import colors from &#39;../constants/colors&#39;;<br><br>const styles = StyleSheet.create({<br>  /// ...<br>});<br><br>export const List = ({ navigation }) =&gt; {<br>  const [data, setData] = React.useState([]);<br><br>  React.useEffect(() =&gt; {<br>    fetch(&#39;https://jsonplaceholder.typicode.com/posts&#39;)<br>      .then((res) =&gt; res.json())<br>      .then((response) =&gt; {<br>        setData(response);<br>      });<br>  }, []);<br><br>  return (<br>    &lt;FlatList<br>      data={data}<br>      style={styles.container}<br>      renderItem={({ item }) =&gt; (<br>        &lt;TouchableOpacity<br>          onPress={() =&gt; navigation.push(&#39;Post&#39;, { post: item })}<br>        &gt;<br>          &lt;View key={item.id} style={styles.item}&gt;<br>            &lt;Text&gt;{item.title}&lt;/Text&gt;<br>          &lt;/View&gt;<br>        &lt;/TouchableOpacity&gt;<br>      )}<br>    /&gt;<br>  );<br>};</pre><pre>// App/screens/Post.js<br>import React from &#39;react&#39;;<br>import { View, StyleSheet, ScrollView } from &#39;react-native&#39;;<br><br>import { Text } from &#39;../components/Text&#39;;<br>import colors from &#39;../constants/colors&#39;;<br><br>const styles = StyleSheet.create({<br>  ...<br>});<br><br>export const Post = ({ route }) =&gt; {<br>  const post = route?.params?.post;<br>  const [comments, setComments] = React.useState([]);<br><br>  React.useEffect(() =&gt; {<br>    fetch(`https://jsonplaceholder.typicode.com/comments?postId=${post.id}`)<br>      .then(res =&gt; res.json())<br>      .then(response =&gt; {<br>        setComments(response);<br>      });<br>  }, []);<br><br>  return (<br>    &lt;ScrollView style={styles.container}&gt;<br>      &lt;Text type=&quot;header&quot;&gt;{post.title}&lt;/Text&gt;<br>      &lt;Text&gt;{post.body}&lt;/Text&gt;<br>      {comments &amp;&amp; comments.length &gt; 0 &amp;&amp; (<br>        &lt;&gt;<br>          &lt;Text type=&quot;header&quot; style={{ marginTop: 20 }}&gt;<br>            Comments<br>          &lt;/Text&gt;<br>          {comments.map(comment =&gt; (<br>            &lt;View key={comment.id} style={styles.item}&gt;<br>              &lt;Text&gt;{comment.body}&lt;/Text&gt;<br>              &lt;Text&gt;{comment.email}&lt;/Text&gt;<br>            &lt;/View&gt;<br>          ))}<br>        &lt;/&gt;<br>      )}<br>    &lt;/ScrollView&gt;<br>  );<br>};</pre><p>Let’s fetch it with React Query instead.</p><h3>Configuring React Query</h3><p>One of the great things about React Query is that it’s just one dependency. If you know me you know I like to minimize dependencies.</p><p>And, since it’s purely JS, you only need to worry about installing it from NPM.</p><pre>npm install --save react-query</pre><p>Once that’s complete we need to set up the QueryClient and QueryClientProvider. These are used to manage the &quot;magic&quot; that React Query provides us (such as caching).</p><p>So, at the root of my project, I’m going to set up the provider:</p><pre>// App/index.js<br><br>import React from &#39;react&#39;;<br>import { StatusBar } from &#39;expo-status-bar&#39;;<br>import { NavigationContainer } from &#39;@react-navigation/native&#39;;<br>import { QueryClient, QueryClientProvider } from &#39;react-query&#39;;<br><br>import { Main } from &#39;./navigation/Main&#39;;<br><br>const queryClient = new QueryClient();<br><br>export default function App() {<br>  return (<br>    &lt;&gt;<br>      &lt;StatusBar style=&quot;auto&quot; /&gt;<br>      &lt;NavigationContainer&gt;<br>        &lt;QueryClientProvider client={queryClient}&gt;<br>          &lt;Main /&gt;<br>        &lt;/QueryClientProvider&gt;<br>      &lt;/NavigationContainer&gt;<br>    &lt;/&gt;<br>  );<br>}</pre><h3>Posts Query</h3><p>With that done let’s migrate over the request that grabs all of the posts.</p><pre>// App/screens/List.js<br><br>import React from &#39;react&#39;;<br>import { View, StyleSheet, FlatList, TouchableOpacity } from &#39;react-native&#39;;<br>import { useQuery } from &#39;react-query&#39;;<br><br>// ...<br><br>export const List = ({ navigation }) =&gt; {<br>  /*<br>  const [data, setData] = React.useState([]);<br><br>  React.useEffect(() =&gt; {<br>    fetch(&#39;https://jsonplaceholder.typicode.com/posts&#39;)<br>      .then(res =&gt; res.json())<br>      .then(response =&gt; {<br>        setData(response);<br>      });<br>  }, []);<br>  */<br>  const { data } = useQuery(&#39;posts&#39;, () =&gt;<br>    fetch(&#39;https://jsonplaceholder.typicode.com/posts&#39;).then((res) =&gt;<br>      res.json()<br>    )<br>  );<br><br>  // ...<br>};</pre><p>You can see the difference there (unchanged code is removed for brevity).</p><p>The code is a little bit more succinct but that’s not the main benefit of React Query.</p><p>As you can see with useQuery the first argument is a simple string. This caches and tracks the result of that query.</p><p>It’s important to note that the key needs to be unique to that request (to <a href="https://jsonplaceholder.typicode.com/posts).">https://jsonplaceholder.typicode.com/posts).</a></p><p>The second argument is how we actually get the data. It either needs to resolve data or throw an error.</p><p>But still, the caching isn’t the only benefit here…</p><p>The initial fetch implementation was super basic. We don’t manage:</p><ul><li>request states (loading, fetching, error)</li><li>errors</li></ul><p>Let alone refetching data or caching it.</p><p>And guess what! That’s all stuff that React Query gives you for free.</p><p>If we take a look at the object returned from userQuery we can see all that is available to us</p><h3>Comments Query</h3><p>The comments query is a little bit more complex… Let’s get it set up.</p><pre>// App/screens/Post.js<br><br>import React from &#39;react&#39;;<br>import { View, StyleSheet, ScrollView } from &#39;react-native&#39;;<br>import { useQuery } from &#39;react-query&#39;;<br><br>// ...<br><br>export const Post = ({ route }) =&gt; {<br>  const post = route?.params?.post;<br>  /*<br>  React.useEffect(() =&gt; {<br>    fetch(`https://jsonplaceholder.typicode.com/comments?postId=${post.id}`)<br>      .then(res =&gt; res.json())<br>      .then(response =&gt; {<br>        setComments(response);<br>      });<br>  }, []);<br>  */<br><br>  const { data: comments } = useQuery([&#39;comments&#39;, post.id], () =&gt;<br>    fetch(<br>      `https://jsonplaceholder.typicode.com/comments?postId=${post.id}`,<br>    ).then(res =&gt; res.json()),<br>  );<br><br>  return ...;<br>};</pre><p>Syntax is a bit different here… why? Well the query key (the first argument to useQuery) can be anything serializable (string, array, object). So in this case we’re creating a key that will cache comments per post (rather than globally).</p><p>Let’s try this out… I’m going to turn on <a href="https://nshipster.com/network-link-conditioner/">Network Link Conditioner</a> (which you can <a href="https://www.reactnativeschool.com/progressive-image-loading-in-react-native">learn more about in our post about progressive image loading</a>) so I have a painfully slow connection.</p><p>Watch the gif below… what do you see?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/238/0*ulum7hbKkIKYdoB5.gif" /></figure><p>When we make our first request to a post’s comments the request is slooow. But when we make our second request? Instant!</p><p>Why?</p><p>Because we’re not making a request — we’re using cached data. Caching we get for free from React Query.</p><p>We just barely scratched the surface of React Query today but I’m finding it to be a powerful library that handles a lot of the simple, and not so simple, things that need to be done when making remote data requests.</p><p>Be sure to <a href="https://react-query.tanstack.com/overview">dive into the official docs</a>. I’m struggling to find a reason why <em>not</em> to use this library.</p><p>Questions/comments/concerns? <a href="https://twitter.com/learn_rn">Let us know on Twitter</a>.</p><p><a href="https://github.com/ReactNativeSchool/react-query-intro">Final code</a>.</p><p><em>Originally published at </em><a href="https://www.reactnativeschool.com/how-to-get-started-with-react-query-migrate-from-fetch"><em>https://www.reactnativeschool.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=18fb426c3760" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-react-native-log/how-to-get-started-with-react-query-migrate-from-fetch-18fb426c3760">How to Get Started with React Query — Migrate from Fetch</a> was originally published in <a href="https://medium.com/the-react-native-log">The React Native Log</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Implementing Cube in React Native]]></title>
            <link>https://medium.com/the-react-native-log/implementing-cube-in-react-native-cb61b9a7e8c3?source=rss----deee1de989f---4</link>
            <guid isPermaLink="false">https://medium.com/p/cb61b9a7e8c3</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[interaction]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[react-native]]></category>
            <dc:creator><![CDATA[Youngchan J]]></dc:creator>
            <pubDate>Mon, 02 Sep 2019 12:02:55 GMT</pubDate>
            <atom:updated>2019-09-02T12:02:55.655Z</atom:updated>
            <content:encoded><![CDATA[<p>While reading <a href="https://medium.com/u/7b85933009e7">Jake Murzy</a>’s post: <a href="https://commitocracy.com/implementing-foldview-in-react-native-e970011f98b8#.k95f793qe"><em>Implement FoldView in React Native</em></a> and understanding how a view can rotate around its shifted origin, I was inspired another UI challenge, rendering an interactive cube using 6 views with different origins. I know you can’t resist your temper to make the following cube. Don’t worry, you will be guided to do it through this post. Let’s move on!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/372/1*AbwhRt_U5UgkfWNo7ULpPg.gif" /></figure><h4>Interaction</h4><p>In order to rotate a view as you drag it, it is required to get information about where you touch and drag. <a href="https://facebook.github.io/react-native/docs/panresponder.html">PanResponder</a> in React Native makes you able to do it. Here’s a simple example of interactive view:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f49396182095d25cdb42bd50b3ffa74b/href">https://medium.com/media/f49396182095d25cdb42bd50b3ffa74b/href</a></iframe><p>As you drag the view, handlePanResponderView function is consistently called and change the style of the view: rotateX and rotateY. dx and dy are the distance of the gesture since your touch started and we want to rotate the view further as you drag further. Simply, rotateX and rotateY can be set as dx and dy. Don’t forget that rotateX and rotateY takes only string format of ‘XXdeg’.</p><p>dx and dy are assigned to y and x respectively since the view will rotate horizontally around y-axis as it is dragged horizontally and vice versa. Similarly, the reason of additive inverse of dy shown in line number 27, is to make the view rotate in the same direction of your touch. It is totally up to you how you will rotate it!</p><p>Using <a href="https://facebook.github.io/react-native/docs/direct-manipulation.html">setNativeProps</a> method upon the view, it is possible to directly change its style without using state/prop and triggering a re-render of the entire subtree, which is useful regarding performance especially when we are about to change the style rapidly as dragging. This is s0-called direct manipulation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/372/1*QjcEtyvAnGwviuvMjbvxbA.gif" /></figure><p>Cool! Now, it rotates in three-dimensional space following your gesture. Have you noticed it is rotating around it’s center in xy-plane? Yes, it is the default origin where rotateX and rotateY use. In order to achieve cube-like rotation, we will shift it’s origin somewhere behind it in z-axis. Forget rotateX and rotateY from now on, but rather, we are going to use matrix.</p><h4>Shifting Origin</h4><p>React Native supports matrix in <a href="https://facebook.github.io/react-native/docs/transforms.html">Transforms</a> where you can change origins. If you are not sure about how rotation matrix works, I recommend you to read <a href="https://commitocracy.com/implementing-foldview-in-react-native-e970011f98b8#.k95f793qe">this post</a> first which was mentioned earlier.</p><p>Since it is rotating about two arbitrary axes, the following general rotation matrix will be used. Don’t freak out. It is a simple plugging-in work. You can plug in zero to one of three variables: alpha, beta, and gamma.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/642/1*8kzkhBCiEtGPSvZKTD5kxg.png" /><figcaption>from <a href="http://inside.mines.edu/fs_home/gmurray/ArbitraryAxisRotation/">inside.mines.edu</a></figcaption></figure><p>Here, I have plugged in zero to gamma and assigned dx and dy to alpha and beta which are rotation degree in x and y axes respectively.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8f31d09d216825299e3ff08b2fe5780f/href">https://medium.com/media/8f31d09d216825299e3ff08b2fe5780f/href</a></iframe><p>Similar to <a href="https://gist.github.com/jmurzy/a4d794c9342504e2ccb81550d7ca2ed3#file-foldview-transformutil-rotatex-js">rotateX method</a> used in react-native-foldView, this rotateXY will spin a view around x and y axes. Then, this method suppose to be invoked as you drag.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1adc63acfcfd4018504480876b73ac4e/href">https://medium.com/media/1adc63acfcfd4018504480876b73ac4e/href</a></iframe><p>Considering the square as the front side of a cube, its origin should fall back half-length of the side in z-axis. Now, it is ready to spin the square around shifted origin! Here is the demo:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/372/1*jTV4PM6dRiEmRYZQVioVYQ.gif" /></figure><p>Comparing this to the previous, it is clear that it rotates around its origin shfited back by half-length of the side in z-axis. Let’s fill the other sides too.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/965a4ce32cf5674dbd61a80a51693211/href">https://medium.com/media/965a4ce32cf5674dbd61a80a51693211/href</a></iframe><p>Since dx and dy we are assigning to rotateXY method can be considered as rotation degrees, you can render left, right, and back side of a cube by simply adding -90, 90, and 180 to dx respectively. Here’s the demo again:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/372/1*TOXfZzEZICIqTaggQ4xKsQ.gif" /></figure><p>It is a little different story for rendering the top and bottom. If you render them by simply adding and substituting 90 to dy, it won’t rotate as you expected since they are on different plane. I used xz-plane by plugging in zero to beta from the general rotation matrix shown above. Here’s another rotate method for the top and bottom.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/52d33aa2138de09bcb6b89778df1a081/href">https://medium.com/media/52d33aa2138de09bcb6b89778df1a081/href</a></iframe><p>Add the following gist in your handlePanResponder method and your top and bottom views will spin perfectly.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/df58a723a3fe18e28194c23fd5390b91/href">https://medium.com/media/df58a723a3fe18e28194c23fd5390b91/href</a></iframe><p>Perfect! Were you able to play with the cube I have shown in the first demo? You can check the <a href="https://github.com/ochanje210/react-native-cube">complete code here</a> for your convenience.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cb61b9a7e8c3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-react-native-log/implementing-cube-in-react-native-cb61b9a7e8c3">Implementing Cube in React Native</a> was originally published in <a href="https://medium.com/the-react-native-log">The React Native Log</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using HTTP3/QUIC with Cronet In Your Mobile App]]></title>
            <link>https://medium.com/the-react-native-log/using-cronet-in-your-mobile-app-7dda3a89c132?source=rss----deee1de989f---4</link>
            <guid isPermaLink="false">https://medium.com/p/7dda3a89c132</guid>
            <category><![CDATA[chromium]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[quic]]></category>
            <category><![CDATA[react-native]]></category>
            <dc:creator><![CDATA[Akshet Pandey]]></dc:creator>
            <pubDate>Mon, 02 Sep 2019 12:02:10 GMT</pubDate>
            <atom:updated>2019-09-02T12:02:10.644Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vzjky7wsR33VhQt30lKmvQ.png" /></figure><h4>Faster downloads, lower latencies, disconnect tolerance, now in your iOS/Android and react-native app!</h4><h3>Wait, there is an HTTP3?</h3><p>Currently in a <a href="https://quicwg.org/base-drafts/draft-ietf-quic-http.html">draft stage</a>, IETF and the <a href="https://quicwg.org/">QUIC working group</a> are working on finishing HTTP3 and the QUIC specification.</p><p>In the simplest of terms, HTTP3 is HTTP2 over QUIC.</p><h3>So what exactly is QUIC?</h3><p>QUIC is a network layer protocol implemented over UDP. Simply put, QUIC is an improvement over TCP. It provides much of what TCP does, i.e. a reliable network channel that handles losses, reordering, retransmission, and congestion control/fairness. On top of that, QUIC also provides:</p><ul><li>Dramatically reduced connection establishment time</li><li>Improved congestion control</li><li>Multiplexing without head of line blocking</li><li>Forward error correction</li><li>Connection migration</li></ul><p>This results in high performance in high latency channels, such as those on mobile devices. You can learn more about the advantages of using QUIC here:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FYWiRef3wOYY%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DYWiRef3wOYY&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FYWiRef3wOYY%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/dbd555096de067660b7fd040bbda6649/href">https://medium.com/media/dbd555096de067660b7fd040bbda6649/href</a></iframe><p>Here is my own test implemented in react-native to compare cronet performance on a high latency, low bandwidth channel.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*MZqU7IV12puAHYbtyrHopA.gif" /><figcaption>Left:OkHttp in React Native, Right: OkHttp + Cronet in React Native, both on a slow network with a QUIC capable server</figcaption></figure><h3>What is Cronet?</h3><p>The best description comes from the Cronet <a href="https://chromium.googlesource.com/chromium/src/+/master/components/cronet/README.md">README</a>:</p><blockquote>Cronet is the networking stack of Chromium put into a library for use on mobile. This is the same networking stack that is used in the Chrome browser by over a billion people. It offers an easy-to-use, high performance, standards-compliant, and secure way to perform HTTP requests. Cronet has support for both Android and iOS.</blockquote><p>Cronet is a very well implemented and tested¹ <a href="https://www.chromium.org/developers/design-documents/network-stack">network stack</a> that provides almost everything that a standard app needs from a network layer library, things like DNS, Cookies, SSL/TLS, HTTP(S), HTTP2, Proxy/PAC, OSCP, Websockets, and F̶T̶P̶ (soon to be removed). It also supports <strong>HTTP over </strong><a href="https://en.wikipedia.org/wiki/QUIC"><strong>QUIC</strong></a>, soon to be called <a href="https://en.wikipedia.org/wiki/HTTP/3"><strong>HTTP³</strong></a>². This makes it a very attractive library to use as the network layer for your mobile app.</p><h3>Who is using it?</h3><p>Cronet is used by <a href="https://developer.android.com/guide/topics/connectivity/cronet">Google Chrome, YouTube, Google App, Google Photos, and Maps — Navigation &amp; Transit.</a></p><p>HTTP3/QUIC is already being used or is in development by <a href="https://engineering.fb.com/android/building-zero-protocol-for-fast-secure-mobile-connections/">facebook</a> (<a href="https://github.com/facebookincubator/mvfst">mvfst</a>), <a href="https://eng.uber.com/employing-quic-protocol/">Uber</a>, <a href="https://cloudflare-quic.com/">Cloudflare</a>, <a href="https://www.fastly.com/blog/why-fastly-loves-quic-http3">Fastly</a>, most of <a href="https://cloudplatform.googleblog.com/2018/06/Introducing-QUIC-support-for-HTTPS-load-balancing.html">GCP Load Balancers and CDN</a> and many more, <a href="https://github.com/quicwg/base-drafts/wiki/Implementations">including Apple, Microsoft</a>, and <a href="https://github.com/mozilla/neqo">Mozilla</a>.</p><h3>How do I use QUIC in my app?</h3><p>The simplest way is to integrate cronet and have a backend server or CDN or a proxy like cloudflare that supports QUIC. Most google &amp; GCP services including Youtube support QUIC by default. Cloudflare, Akamai, and Fastly support QUIC but needs to be manually enabled.</p><h3>Using Cronet In Your App</h3><p>Based on whether your app is a native Android app, native iOS app or a react-native app, jump to the appropriate section.</p><h4>Using Cronet in Android</h4><p>If you are starting from scratch, using cronet as the network layer is documented on the <a href="https://developer.android.com/guide/topics/connectivity/cronet">android developer docs</a>. You can use it directly instead of using HttpUrlConnection or OkHttp.</p><p>It comes down to adding a library dependency in your build.gradle file.</p><pre>dependencies {<br>    implementation &#39;com.google.android.gms:play-services-cronet:16.0.0&#39;<br>} </pre><p>Then checking if cronet is available to use:</p><pre>CronetProviderInstaller.installProvider(reactContext).addOnCompleteListener(new OnCompleteListener&lt;Void&gt;() {<br>  @Override<br>  public void onComplete(@NonNull Task&lt;Void&gt; task) {<br>    if (task.isSuccessful()) {<br>      // Setup your code to use cronet here.<br>    }<br>  }<br>});</pre><p>After that follow the instructions to <a href="https://developer.android.com/guide/topics/connectivity/cronet/start#create">create an instance of the engine and send a request</a>.</p><h4>Using Cronet in Android using OkHttp</h4><p>If you already have an app, you are likely using OkHttp and very likely don’t want to rewrite every piece of code that interacts with the OkHttp API.</p><p>Fortunately, it is possible to use cronet with OkHttp. Follow the steps above and then, depending on what other libraries you use, follow one of the two steps below.</p><ol><li>If you are using <strong>Retrofit</strong>. You can use Retrofit.Builder.<a href="https://square.github.io/retrofit/2.x/retrofit/retrofit2/Retrofit.Builder.html#callFactory-okhttp3.Call.Factory-">callFactory</a> to pass in a custom call factory that you can write that works with cronet.</li></ol><p>An example implementation is available here: <a href="https://github.com/akshetpandey/react-native-cronet/blob/master/android/src/main/java/com/akshetpandey/rncronet/RNCronetOkHttpCall.java">RNCronetOkHttpCall.java</a></p><p>2. If you are <strong>NOT using Retrofit</strong>, you can use an OkHttp interceptor to make cronet work for you. This is a less ideal solution, but works mostly fine.</p><p>An example implementation is available here: <a href="https://github.com/akshetpandey/react-native-cronet/blob/master/android/src/main/java/com/akshetpandey/rncronet/RNCronetInterceptor.java">RNCronetInterceptor.java</a></p><p><em>Note: Though the files says RN, the code doesn’t use anything react-native specific.</em></p><h4>Using Cronet in iOS</h4><p>Although cronet works perfectly fine on iOS, it lacks substantial documentation. You can get started by reading <a href="https://chromium.googlesource.com/chromium/src/+/master/components/cronet/ios/Cronet.h">Cronet.h</a> and <a href="https://chromium.googlesource.com/chromium/src/+/master/components/cronet/ios/cronet_consumer/">cronet_consumer</a> sample code. However, once built, using cronet is much easier on iOS than Android.</p><p>Cronet is not officially available as a framework or cocoapod, but you can build it from source following the <a href="https://chromium.googlesource.com/chromium/src/+/master/components/cronet/ios/docs/BUILD.md">build instructions</a>. For your convenience, I have created a <a href="https://github.com/akshetpandey/Cronet.framework">podspec</a> that you can include:</p><pre>pod &#39;Cronet&#39;, &#39;78.0.3888.patch.0.pre&#39;</pre><p>After this you can initialize the engine and have <strong>NSURLSession</strong> and <strong>NSURLConnection</strong> use cronet internally. This is fairly straightforward to do:</p><pre>#include &lt;Cronet/Cronet.h&gt;</pre><pre>...</pre><pre>[Cronet setHttp2Enabled:YES];<br>[Cronet setQuicEnabled:YES];<br>[Cronet setBrotliEnabled:YES];<br>[Cronet setHttpCacheType:CRNHttpCacheTypeDisk];</pre><pre>[Cronet addQuicHint:@&quot;www.google.com&quot; port:443 altPort:443];</pre><pre>[Cronet start];</pre><pre>[Cronet registerHttpProtocolHandler];</pre><p>Sample code to get you started is here: <a href="https://github.com/akshetpandey/react-native-cronet/blob/master/example/ios/example/AppDelegate.m#L22-L33">AppDelegate.m</a></p><h4>Using Cronet in React Native</h4><p>I have made a <a href="https://github.com/akshetpandey/react-native-cronet">react-native library</a> that should make using cronet very simple. Just add it into your package.json</p><pre>yarn add react-native-cronet</pre><p>That is all you need to do for iOS.</p><p>On Android, you need to configure Fresco to also use it by adding the following in your <a href="https://github.com/akshetpandey/react-native-cronet/blob/master/example/android/app/src/main/java/com/example/MainApplication.java">MainApplication.java</a>. This depends on a <a href="https://github.com/react-native-community/cli/pull/653">PR waiting to be merged in react-native-community/cli</a>. In the meantime, you can use <a href="https://www.npmjs.com/package/patch-package">patch-package</a> with that patch.</p><pre>import com.akshetpandey.rncronet.RNCronetFrescoImagePipelineConfig;<br>import com.facebook.imagepipeline.core.ImagePipelineConfig;<br>import com.facebook.react.shell.MainPackageConfig;</pre><pre>public class MainApplication extends Application implements ReactApplication {</pre><pre>  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {<br>    @Override<br>    protected List&lt;ReactPackage&gt; getPackages() {<br>      ImagePipelineConfig pipelineConfig = RNCronetFrescoImagePipelineConfig.build(getApplicationContext());<br>      MainPackageConfig config = new MainPackageConfig.Builder().setFrescoConfig(pipelineConfig).build();<br>      List&lt;ReactPackage&gt; packages = new PackageList(this, config).getPackages();<br>      // Packages that cannot be autolinked yet can be added manually here, for example:<br>      // packages.add(new RNCronetNetworkingPackage());<br>      return packages;<br>    }<br>  }<br>}</pre><p>¹- What is a better way to test a network stack than in Chrome, whose primary job is to fetch assets and data over the network and display them to the user?</p><p>²- QUIC is a general purpose transport layer network protocol built on top of UDP with a user space congestion control and packet loss recovery algorithm that is <a href="https://datatracker.ietf.org/wg/quic/documents/">still being improved</a>. HTTP3 is an application layer protocol that speaks HTTP over QUIC.</p><h3>Hire Me</h3><p>I am looking for new opportunities, you can learn more about me on <a href="https://www.linkedin.com/in/akshet/">LinkedIn</a> and see more of my work on <a href="https://github.com/akshetpandey">GitHub</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7dda3a89c132" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-react-native-log/using-cronet-in-your-mobile-app-7dda3a89c132">Using HTTP3/QUIC with Cronet In Your Mobile App</a> was originally published in <a href="https://medium.com/the-react-native-log">The React Native Log</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Stacks on stacks in React Native]]></title>
            <link>https://medium.com/the-react-native-log/stacks-on-stacks-in-react-native-eb4f8fb9e4c9?source=rss----deee1de989f---4</link>
            <guid isPermaLink="false">https://medium.com/p/eb4f8fb9e4c9</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Charles D. Mangwa]]></dc:creator>
            <pubDate>Fri, 24 May 2019 12:23:56 GMT</pubDate>
            <atom:updated>2019-05-30T12:23:48.908Z</atom:updated>
            <content:encoded><![CDATA[<h3>🥞 Stacks on stacks in React Native</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TnwokhQzTdEJRESSoRaZyg.jpeg" /><figcaption>Let’s talk about stacks! — Credits <a href="https://unsplash.com/photos/qp7WA8AV2x0">NIKLDN</a></figcaption></figure><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FQGtsYDtPezY%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DQGtsYDtPezY&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FQGtsYDtPezY%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/a4f48db36d43767a8307d3cb4eb02a55/href">https://medium.com/media/a4f48db36d43767a8307d3cb4eb02a55/href</a></iframe><p><em>I had the opportunity to talk about this during a </em><a href="https://slides.com/charles-mangwa/rnm-re2019"><em>lightning talk</em></a><em> at </em><a href="http://react-europe.org/"><em>react-europe</em></a><em> 2019 so if you’re more of a video type of person: here you go!</em></p><p>Being a React Native developer has been a great experience lately. More and more bugs I was facing are getting fixed and React Native itself i<a href="https://github.com/react-native-community/discussions-and-proposals/issues/4">s about to get to the next level.</a></p><p>But I always had some really specific things I couldn’t be satisfied with the way they were. It went from rendering Markdown, to <a href="https://medium.com/the-react-native-log/thousand-ways-to-navigate-in-react-native-f7a1e311a0e8">navigating from screens to screens</a>, to <a href="https://medium.com/@CharlesMangwa/introducing-react-data-fetching-2140a1d36cc8">fetching data declaratively</a>, etc.</p><p>Today we’ll be talking about a new problem I’ve been dealing with lately: modals.</p><h4>The Context 🧐</h4><p>Modals are the most common UI elements we use as developers. As soon as we want to display an error, loading, success state, any important message or a specific part of your app: they’re more often than not the answer to our question.</p><p><em>When I talk about modals, in this particular context, </em><a href="https://ux.stackexchange.com/a/90337"><em>you could also consider alert, dialog, popup, etc</em></a><em> as valid synonyms.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*XlHEGoZ83kT4hnoG.png" /><figcaption><em>Currency modal — Credits </em><a href="https://dribbble.com/johnyvino"><em>Johny Vino</em></a></figcaption></figure><p>In the case of mobile applications, it’s fair to say that modals are even more important/used than on the web. Alerts, errors, date pickers, time pickers, etc all of them could be labeled as modals.</p><p>As of today, I’ve mainly tried 2 tools that help you display modals: React Native’s <a href="https://facebook.github.io/react-native/docs/modal">Modal</a> component and React Native Community’s <a href="https://github.com/react-native-community/react-native-modal">react-native-modal</a>. These two are great solutions! Modal uses nativeRCTModalHostView component and react-native-modal uses Modal under the hood and it’s fair to say that: they get the job done.</p><p>However, they didn’t quite match our needs, as we’re about to see in the following section.</p><h4>The Problems 🤒</h4><p>One day, <a href="https://medium.com/u/fd4a07020f4">Irem Lopsum</a>, coworker and good friend of mine came to me with a problem:</p><blockquote>“I can’t find a React Native modal library that just get the job done properly.”</blockquote><p>We’re working together at <a href="https://medium.com/u/f764c3a7252b">colorfy</a> (a design studio based in Berlin and specialized in IoT hardware &amp; software) and I’ve seen him working one very specific app that exacerbated this need. That app has extensive use of modals and dealing with several &lt;Modal /&gt; components, updating local states to toggle their visibility, changing their content, etc: it was just too cumbersome. That’s why his main requirement was:</p><blockquote>1. “Write once, call from anywhere with minimal effort.”</blockquote><p>Next issue (and maybe the most complex one) one was the impossibility of displaying several modals and stacking (😉) them. This sentence may not make a lot of sense, “why would you display multiple modals at once ?!”, but bear with me for this one: we needed it! Unfortunately, both React Native’s Modal and react-native-modal can’t do that (mainly because of how RCTModalHostView they both use works). But this was actually the second requirement:</p><blockquote>2. “Ability to render multiple modals and stack them.”</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/0*xvkHGKF2GIASLebZ.gif" /><figcaption>React Native Animatable <a href="https://github.com/oblador/react-native-animatable/tree/master/Examples/MakeItRain">in action</a>!</figcaption></figure><p>Last one: animations. We really loved the fact that react-native-modal allows you to define your own custom animations (through <a href="https://github.com/oblador/react-native-animatable">react-native-animatable</a>). However, besides the amazing work done by the community with React Native Animatable, we felt that that approach was still a bit too complicated for what we were starting to have in mind.</p><p>As you may have understood, by that time, we already had a pretty solid idea of what we wanted to have and we actually found a perfect example of the API we’d like to have: <a href="https://reactnavigation.org/">React Navigation</a>’s! I’m going to explain why in the next section of this article, but getting inspiration from React Navigation’s API would tick a lot of boxes. It would also help us match another requirement that we couldn’t with the 2 abovementioned existing solutions:</p><blockquote>3. “Easy control over transitions and animation relationship between modals within the stack.”</blockquote><p>All of this so that we could have <em>“overall flexibility to not be limited with what one can do” </em>as <a href="https://medium.com/u/fd4a07020f4">Irem Lopsum</a> told me<em>. </em>You control what’s rendered, how, when, from start to finish and even after that (stacking!). And after a few days of hacking, failing, bouncing ideas back and forth, we finally came up with something that totally satisfied both of us.</p><h4>The Solution 💡</h4><p><strong>React Native Modalfy!</strong><br>This is our answer to all the problems <a href="https://medium.com/u/fd4a07020f4">Irem Lopsum</a> was facing. The API we came up with is something that we hope you’ll see as:</p><blockquote>Simple, fast to implement yet totally flexible.</blockquote><p>Using <a href="https://colorfy-software.gitbook.io/react-native-modalfy/">react-native-modalfy</a> could be summed up in 3 steps:</p><h4>1. You add &lt;ModalProvider /&gt;</h4><p>It’s a normal Provider that’s going to give you access to your modal across your whole app thanks to <a href="https://reactjs.org/docs/context.html">React’s Context API</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RIjB7B0akI3Gl7ipxuPQoA.png" /></figure><h4>2. You set up your stack with createModalStack()</h4><p>This is where all the magic happens. You’ll have to set up all your modals so that the library can access them before render time. From there you’ll feed ModalProvider the output ofcreateModalStack() through it’s only variable: stack. If you’re familiar with React Navigation, this API might actually ring a bell and that’s why we took inspiration from it: looked really straightforward to us!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*26XyFKA17bbkePHCIVKP1g.png" /></figure><h4>3. You use your modals with openModal() / closeModal()</h4><p>From there you can open as many modal as you want from wherever you want in your app. React Native Modalfy lets you use this function (and other things) from the modal prop. You can access this prop from your modal component props, or if you’re anywhere else in your app, just use withModal HOC or useModal hook to get the job done!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sUqcGS_s_seJykk314JuLw.png" /></figure><p>And that’s it! While still being really simple to set up, React Native Modalfy gives you so much flexibility on where to display your modals, what to display and even <em>how</em>,<em> </em>as we gonna see in a minute!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/370/1*cWDkz3Sd-YGYj5NfO95o2Q.png" /><figcaption>Customer satisfaction: 💯</figcaption></figure><h4>Examples 🔬</h4><p>As I mentioned above, the most interesting part of the library is what createModalStack() allows you to do. I gave you a little glimpse of what it could do earlier but here it is in full bloom:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iDkZj7QxaQs8rWaHoK-nug.png" /></figure><p>And I want to bring your attention over transitionOptions because you can have a lot of fun with this one. It basically sets transitions based on the animated value React Native Modalfy uses under the hood to animate your stack. Based on that animated value, you’ll be able to setup custom interpolations that will be applied to your modal component.</p><p>So let me illustrate with a few examples what you can achieve with that and how easy it would be:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FusAU2pcURh8%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DusAU2pcURh8&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FusAU2pcURh8%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/3d6c187fb60709c6ad4961942799c8e4/href">https://medium.com/media/3d6c187fb60709c6ad4961942799c8e4/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6ce514df3df21f0fcca13f32bf892986/href">https://medium.com/media/6ce514df3df21f0fcca13f32bf892986/href</a></iframe><p>or you could do something like:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FUPDSPjj4dyU%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DUPDSPjj4dyU&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FUPDSPjj4dyU%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/d335d1c269b33f6b01e7b68cc57fbfb2/href">https://medium.com/media/d335d1c269b33f6b01e7b68cc57fbfb2/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3c5ac6843e26db0a1d2c50cd20ed3cb4/href">https://medium.com/media/3c5ac6843e26db0a1d2c50cd20ed3cb4/href</a></iframe><p>maybe a little bit of:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FLkHFK5zZMI8%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DLkHFK5zZMI8&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FLkHFK5zZMI8%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/3c90254737baa0ba28d4b42e2de91f4c/href">https://medium.com/media/3c90254737baa0ba28d4b42e2de91f4c/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cc47ef7df3cd63bb2d3c8a5cfde81ebe/href">https://medium.com/media/cc47ef7df3cd63bb2d3c8a5cfde81ebe/href</a></iframe><p>and how about:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FAJ1P9e7iD38%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DAJ1P9e7iD38&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FAJ1P9e7iD38%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/811661cbf576ea9cb6488c07f8ab9e8b/href">https://medium.com/media/811661cbf576ea9cb6488c07f8ab9e8b/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/137d7716935e34a1a355726137fb5d37/href">https://medium.com/media/137d7716935e34a1a355726137fb5d37/href</a></iframe><p>As you can see: your imagination is the only limit! All this only took <a href="https://medium.com/u/fd4a07020f4">Irem Lopsum</a> between 35 and 40 lines of code. As soon as you know how to use React Native styles and interpolation: that’s it, you’re good to go! 🙌</p><p>And that’s it, folks! We’re totally opened to any feedback, idea, critic, PR you may have. Just chime in on the repo or ping us <a href="https://twitter.com/@Charles_Mangwa">@Charles_Mangwa</a>/<a href="https://twitter.com/iremlopsum">@iremlopsum</a>. Until then, simply run yarn add react-native-modalfy and have fun!</p><p><a href="https://react-native-modalfy.now.sh/docs">What &amp; why</a></p><p>Oh btw! If you’re interested: <a href="https://medium.com/u/f764c3a7252b">colorfy</a> is actively hiring in Berlin! We’re looking for people into React Native, but also back-end, marketing, product design, hardware, project management, and even more. Just check out our careers section and maybe see you there soon (tell them Charles sent you 😁)!</p><p><a href="http://colorfy.me/jobs/">Jobs - colorfy</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eb4f8fb9e4c9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-react-native-log/stacks-on-stacks-in-react-native-eb4f8fb9e4c9">Stacks on stacks in React Native</a> was originally published in <a href="https://medium.com/the-react-native-log">The React Native Log</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Best Practices for Capturing User Feedback in React Native]]></title>
            <link>https://medium.com/the-react-native-log/best-practices-for-capturing-user-feedback-in-react-native-33629431c0d?source=rss----deee1de989f---4</link>
            <guid isPermaLink="false">https://medium.com/p/33629431c0d</guid>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[Spencer Carli]]></dc:creator>
            <pubDate>Wed, 27 Mar 2019 22:17:01 GMT</pubDate>
            <atom:updated>2019-03-27T22:17:01.574Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jr2tUtJVqRJhRb83e0_KnQ.jpeg" /><figcaption>A random image for effect.</figcaption></figure><h4>Nothing beats getting real feedback from your users — but how should you go about capturing that feedback? In this tutorial we’ll discuss when you should prompt them, how you should prompt them, and what tools you can use to capture that feedback.</h4><blockquote><em>This tutorial was originally published on </em><a href="https://www.reactnativeschool.com/best-practices-for-capturing-user-feedback-in-react-native"><em>React Native School</em></a><em>. Give it a visit if you want to see 75+ React Native tutorials!</em></blockquote><p>I’ve got a pet peeve — when apps ask for feedback/a review at bad times/in bad ways:</p><ul><li>When I first open the app</li><li>In the middle of an important action (like checking out)</li><li>They hijack my screen and don’t let me do anything unless I do their feedback thing</li></ul><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FlWIrjSp4kCM%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DlWIrjSp4kCM&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FlWIrjSp4kCM%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/ab22cb458f3c34771b3002c2e8b8c2da/href">https://medium.com/media/ab22cb458f3c34771b3002c2e8b8c2da/href</a></iframe><blockquote><em>Thanks to </em><a href="https://instabug.com/?utm_source=reactnativeschool"><em>Instabug</em></a><em> for sponsoring this lesson! If you’re looking for an all-in-one solution to capture user feedback, bug reports, crash reports, and more check them out! I’ll have more info on how you could use them in the context of capture user feedback later in the lesson.</em></blockquote><h3>Good Times &amp; Ways to Ask for Feedback</h3><p>Before we get into the hands on part, lets just drop a few times/places you could ask for feedback and get good responses:</p><ol><li><strong>When the user completes an important action (like checking out).</strong> This means detecting when an action is complete and not just asking for feedback after a given amount of time.</li><li><strong>When they take a similar action many times.</strong> Say your app gives them a random joke. Say they’ve pressed the “New Joke” button 15 times. That would be a good opportunity to ask why they aren’t rolling on the floor gasping for air from your quality jokes you jacked from the latest Netflix stand up special.</li><li><strong>When they’re vigorously shaking their phone out of frustration.</strong> Maybe ask if they’re having issues? I mean how often do you see people shaking their phone out of joy?</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/413/0*9F8w54kqJv7ilbKV.gif" /></figure><h3>Navigation Setup for Capturing User Feedback</h3><p>What’s this look like in practice? Let’s look at it.</p><h3>The Example App</h3><p>First we’ll set up our example app. It’s a revolutionary new app called <em>Clargue</em> that will, on demand, generate a random color for you. Here’s the code we’re starting with.</p><pre>import React from &#39;react&#39;;<br>import { Text, View, Button, AsyncStorage } from &#39;react-native&#39;;<br>import randomColor from &#39;random-color&#39;;<br>import {<br>  createStackNavigator,<br>  createAppContainer,<br>  createSwitchNavigator,<br>} from &#39;react-navigation&#39;;<br><br>class RandomColor extends React.Component {<br>  state = {<br>    backgroundColor: randomColor().hexString(),<br>  };<br><br>  newColor = () =&gt; {<br>    this.setState(state =&gt; ({<br>      backgroundColor: randomColor().hexString(),<br>    }));<br>  };<br><br>  signOut = () =&gt; {<br>    AsyncStorage.removeItem(&#39;isOnboarded&#39;);<br>    this.props.navigation.navigate(&#39;Onboarding&#39;);<br>  };<br><br>  render() {<br>    return (<br>      &lt;View<br>        style={{<br>          flex: 1,<br>          alignItems: &#39;center&#39;,<br>          justifyContent: &#39;center&#39;,<br>          backgroundColor: this.state.backgroundColor,<br>        }}<br>      &gt;<br>        &lt;View<br>          style={{<br>            backgroundColor: &#39;rgba(255, 255, 255, 0.5)&#39;,<br>            borderRadius: 10,<br>            paddingHorizontal: 10,<br>            paddingVertical: 5,<br>          }}<br>        &gt;<br>          &lt;Text<br>            style={{<br>              fontSize: 20,<br>              color: &#39;#000&#39;,<br>            }}<br>          &gt;<br>            {this.state.backgroundColor}<br>          &lt;/Text&gt;<br>        &lt;/View&gt;<br>        &lt;Button title=&quot;New Color&quot; onPress={this.newColor} /&gt;<br>        &lt;Button title=&quot;Sign Out&quot; onPress={this.signOut} /&gt;<br>      &lt;/View&gt;<br>    );<br>  }<br>}<br><br>class Entry extends React.Component {<br>  componentDidMount() {<br>    AsyncStorage.getItem(&#39;isOnboarded&#39;).then(isOnboarded =&gt; {<br>      if (isOnboarded == &#39;true&#39;) {<br>        this.props.navigation.navigate(&#39;Main&#39;);<br>      } else {<br>        this.props.navigation.navigate(&#39;Onboarding&#39;);<br>      }<br>    });<br>  }<br><br>  render() {<br>    return null;<br>  }<br>}<br><br>const Onboard1 = ({ navigation }) =&gt; (<br>  &lt;View style={{ flex: 1, alignItems: &#39;center&#39;, justifyContent: &#39;center&#39; }}&gt;<br>    &lt;Text style={{ fontSize: 30, marginBottom: 10 }}&gt;Welcome to Clargue&lt;/Text&gt;<br>    &lt;Text&gt;The Biggest Innovation in&lt;/Text&gt;<br>    &lt;Text&gt;Random Color Generation&lt;/Text&gt;<br>    &lt;Button<br>      title=&quot;Learn More&quot;<br>      onPress={() =&gt; navigation.navigate(&#39;Onboard2&#39;)}<br>    /&gt;<br>  &lt;/View&gt;<br>);<br><br>const Onboard2 = ({ navigation }) =&gt; (<br>  &lt;View<br>    style={{<br>      flex: 1,<br>      alignItems: &#39;center&#39;,<br>      justifyContent: &#39;center&#39;,<br>      paddingHorizontal: 40,<br>    }}<br>  &gt;<br>    &lt;Text style={{ marginBottom: 30 }}&gt;<br>      We use big data and machine learning to get money from investors...<br>    &lt;/Text&gt;<br>    &lt;Text&gt;and a basic algorithm from Github to select your colors.&lt;/Text&gt;<br>    &lt;Button<br>      title=&quot;Get Started&quot;<br>      onPress={() =&gt; {<br>        AsyncStorage.setItem(&#39;isOnboarded&#39;, &#39;true&#39;);<br>        navigation.navigate(&#39;Main&#39;);<br>      }}<br>    /&gt;<br>  &lt;/View&gt;<br>);<br><br>const Navigator = createSwitchNavigator({<br>  Entry: {<br>    screen: Entry,<br>  },<br>  Onboarding: createStackNavigator(<br>    {<br>      Onboard1: {<br>        screen: Onboard1,<br>      },<br>      Onboard2: {<br>        screen: Onboard2,<br>      },<br>    },<br>    {<br>      headerMode: &#39;none&#39;,<br>    }<br>  ),<br>  Main: {<br>    screen: RandomColor,<br>  },<br>});<br><br>export default createAppContainer(Navigator);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/392/0*kNpkdRGp_5gPqmrp.gif" /></figure><h3>The Feedback Screen</h3><p>You can present the request for feedback/bug report/review in a variety of ways. I think the easiest is going to be by adding a global modal screen that you can access and present from anywhere in your app. For our app I’ll do this by creating a new screen (which in a real situation would likely have a form of some sort) and then adding a stack navigator as our new root navigator.</p><pre>// ...<br><br>const Navigator = createSwitchNavigator({<br>  Entry: {<br>    screen: Entry,<br>  },<br>  Onboarding: createStackNavigator(<br>    {<br>      Onboard1: {<br>        screen: Onboard1,<br>      },<br>      Onboard2: {<br>        screen: Onboard2,<br>      },<br>    },<br>    {<br>      headerMode: &#39;none&#39;,<br>    }<br>  ),<br>  Main: {<br>    screen: RandomColor,<br>  },<br>});<br><br>const FeedbackForm = () =&gt; (<br>  &lt;View style={{ flex: 1, justifyContent: &#39;center&#39;, paddingHorizontal: 40 }}&gt;<br>    &lt;Text&gt;<br>      How are you liking Clargue? We&#39;ll use your feedback to file an issue on<br>      the open source library - but don&#39;t worry! We&#39;ll say it&#39;s a priority<br>      because our business depends on a fix!<br>    &lt;/Text&gt;<br>  &lt;/View&gt;<br>);<br><br>const Modals = createStackNavigator(<br>  {<br>    Navigator: {<br>      screen: Navigator,<br>    },<br>    Feedback: {<br>      screen: createStackNavigator({<br>        FeedbackForm: {<br>          screen: FeedbackForm,<br>          navigationOptions: ({ navigation }) =&gt; ({<br>            headerTitle: &#39;Feedback&#39;,<br>          }),<br>        },<br>      }),<br>    },<br>  },<br>  {<br>    headerMode: &#39;none&#39;,<br>    mode: &#39;modal&#39;,<br>  }<br>);<br><br>export default createAppContainer(Modals);</pre><p>With this setup we can now open the Feedback screen from anywhere in our app via this.props.navigation.navigate(&#39;Feedback&#39;) and it will appear over top of the current screen.</p><h3>Presenting Feedback Form after a Given Number of Actions</h3><p>We’ll just cover one of the scenarios I outlined before: requesting feedback after a given number of actions.</p><p>We’ll just do it based on actions in a single component but you could do this on a larger scale. Say you want to ask for feedback after 20 total actions instead of 5 single actions. You could track the number of actions in Redux/Context/whatever and as that value hits the desired number prompt them (just don’t do it if they’re doing something important)!</p><p>All I’m going to do is increment a clickCount on state whenever they take an action. When it hits my desired number it will reset the number and open the feedback screen.</p><pre>// ...<br><br>class RandomColor extends React.Component {<br>  state = {<br>    backgroundColor: randomColor().hexString(),<br>    clickCount: 0,<br>  };<br><br>  newColor = () =&gt; {<br>    if (this.state.clickCount &gt; 5) {<br>      this.props.navigation.navigate(&#39;Feedback&#39;);<br>      this.setState({ clickCount: 0 });<br>    } else {<br>      this.setState(state =&gt; ({<br>        backgroundColor: randomColor().hexString(),<br>        clickCount: state.clickCount + 1,<br>      }));<br>    }<br>  };<br><br>  // ...<br>}<br><br>// ...</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/392/0*uoY0fjqnRk5oDpbY.gif" /></figure><h3>Give the User a Way Out</h3><p>Finally, don’t forget to give the user a clear way to get out of submitting feedback! Maybe that don’t have the time, don’t want to, or just don’t know WTF is going on. Make it clear to get out. Leave a good impression.</p><p>Remember, you’re building an app that provides value to them. Feedback/reviews will come eventually. Don’t force it.</p><p>That said, let’s add a close button to the header.</p><pre>const Modals = createStackNavigator(<br>  {<br>    Navigator: {<br>      screen: Navigator,<br>    },<br>    Feedback: {<br>      screen: createStackNavigator({<br>        FeedbackForm: {<br>          screen: FeedbackForm,<br>          navigationOptions: ({ navigation }) =&gt; ({<br>            headerTitle: &#39;Feedback&#39;,<br>            headerRight: (<br>              &lt;Button title=&quot;Close&quot; onPress={() =&gt; navigation.pop()} /&gt;<br>            ),<br>          }),<br>        },<br>      }),<br>    },<br>  },<br>  {<br>    headerMode: &#39;none&#39;,<br>    mode: &#39;modal&#39;,<br>  }<br>);<br><br>export default createAppContainer(Modals);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/392/0*scK-6B23o-ODLgtj.gif" /></figure><h3>Making Life Easier: Outsourcing Feedback &amp; Bug Report Capturing</h3><p>Obviously this is just one part of capturing feedback and bug reports. You also need to setup something on the backend to capture that feedback and present it to developers/product owners. That’s more work for you and more code for you to maintain.</p><p>I like to keep my focus on the product I’m building, not so much the support system that keep things going. Capturing feedback and bug reporting is one of those things that’s necessary but I don’t want to build.</p><p>That’s why I reach for tools like <a href="https://instabug.com/?utm_source=reactnativeschool">Instabug</a> to handle that for me. Not only can you capture user feedback and bug reports but also use it to detect production exceptions and crashes — an absolutely critical piece of the puzzle for any production app.</p><p>I’ve been happy with their service — it works when I need it and stays out of the way the rest of the time.</p><p>If you’re interest in seeing how to actually integrate and use their service check out the <a href="https://reactnativeschool.com/debugging-in-development-and-production">How to Debug React Native Apps in Development and Production</a> class here on React Native School!</p><h3>Links &amp; Resources</h3><ul><li><a href="https://instabug.com/?utm_source=reactnativeschool">Instabug</a></li><li><a href="https://www.npmjs.com/package/react-native-shake">Detecting Device Shake</a></li></ul><h3>Final Code</h3><pre>import React from &#39;react&#39;;<br>import { Text, View, Button, AsyncStorage } from &#39;react-native&#39;;<br>import randomColor from &#39;random-color&#39;;<br>import {<br>  createStackNavigator,<br>  createAppContainer,<br>  createSwitchNavigator,<br>} from &#39;react-navigation&#39;;<br><br>class RandomColor extends React.Component {<br>  state = {<br>    backgroundColor: randomColor().hexString(),<br>    clickCount: 0,<br>  };<br><br>  newColor = () =&gt; {<br>    if (this.state.clickCount &gt; 5) {<br>      this.props.navigation.navigate(&#39;Feedback&#39;);<br>      this.setState({ clickCount: 0 });<br>    } else {<br>      this.setState(state =&gt; ({<br>        backgroundColor: randomColor().hexString(),<br>        clickCount: state.clickCount + 1,<br>      }));<br>    }<br>  };<br><br>  signOut = () =&gt; {<br>    AsyncStorage.removeItem(&#39;isOnboarded&#39;);<br>    this.props.navigation.navigate(&#39;Onboarding&#39;);<br>  };<br><br>  render() {<br>    return (<br>      &lt;View<br>        style={{<br>          flex: 1,<br>          alignItems: &#39;center&#39;,<br>          justifyContent: &#39;center&#39;,<br>          backgroundColor: this.state.backgroundColor,<br>        }}<br>      &gt;<br>        &lt;View<br>          style={{<br>            backgroundColor: &#39;rgba(255, 255, 255, 0.5)&#39;,<br>            borderRadius: 10,<br>            paddingHorizontal: 10,<br>            paddingVertical: 5,<br>          }}<br>        &gt;<br>          &lt;Text<br>            style={{<br>              fontSize: 20,<br>              color: &#39;#000&#39;,<br>            }}<br>          &gt;<br>            {this.state.backgroundColor}<br>          &lt;/Text&gt;<br>        &lt;/View&gt;<br>        &lt;Button title=&quot;New Color&quot; onPress={this.newColor} /&gt;<br>        &lt;Button title=&quot;Sign Out&quot; onPress={this.signOut} /&gt;<br>      &lt;/View&gt;<br>    );<br>  }<br>}<br><br>class Entry extends React.Component {<br>  componentDidMount() {<br>    AsyncStorage.getItem(&#39;isOnboarded&#39;).then(isOnboarded =&gt; {<br>      if (isOnboarded == &#39;true&#39;) {<br>        this.props.navigation.navigate(&#39;Main&#39;);<br>      } else {<br>        this.props.navigation.navigate(&#39;Onboarding&#39;);<br>      }<br>    });<br>  }<br><br>  render() {<br>    return null;<br>  }<br>}<br><br>const Onboard1 = ({ navigation }) =&gt; (<br>  &lt;View style={{ flex: 1, alignItems: &#39;center&#39;, justifyContent: &#39;center&#39; }}&gt;<br>    &lt;Text style={{ fontSize: 30, marginBottom: 10 }}&gt;Welcome to Clargue&lt;/Text&gt;<br>    &lt;Text&gt;The Biggest Innovation in&lt;/Text&gt;<br>    &lt;Text&gt;Random Color Generation&lt;/Text&gt;<br>    &lt;Button<br>      title=&quot;Learn More&quot;<br>      onPress={() =&gt; navigation.navigate(&#39;Onboard2&#39;)}<br>    /&gt;<br>  &lt;/View&gt;<br>);<br><br>const Onboard2 = ({ navigation }) =&gt; (<br>  &lt;View<br>    style={{<br>      flex: 1,<br>      alignItems: &#39;center&#39;,<br>      justifyContent: &#39;center&#39;,<br>      paddingHorizontal: 40,<br>    }}<br>  &gt;<br>    &lt;Text style={{ marginBottom: 30 }}&gt;<br>      We use big data and machine learning to get money from investors...<br>    &lt;/Text&gt;<br>    &lt;Text&gt;and a basic algorithm from Github to select your colors.&lt;/Text&gt;<br>    &lt;Button<br>      title=&quot;Get Started&quot;<br>      onPress={() =&gt; {<br>        AsyncStorage.setItem(&#39;isOnboarded&#39;, &#39;true&#39;);<br>        navigation.navigate(&#39;Main&#39;);<br>      }}<br>    /&gt;<br>  &lt;/View&gt;<br>);<br><br>const Navigator = createSwitchNavigator({<br>  Entry: {<br>    screen: Entry,<br>  },<br>  Onboarding: createStackNavigator(<br>    {<br>      Onboard1: {<br>        screen: Onboard1,<br>      },<br>      Onboard2: {<br>        screen: Onboard2,<br>      },<br>    },<br>    {<br>      headerMode: &#39;none&#39;,<br>    }<br>  ),<br>  Main: {<br>    screen: RandomColor,<br>  },<br>});<br><br>const FeedbackForm = () =&gt; (<br>  &lt;View style={{ flex: 1, justifyContent: &#39;center&#39;, paddingHorizontal: 40 }}&gt;<br>    &lt;Text&gt;<br>      How are you liking Clargue? We&#39;ll use your feedback to file an issue on<br>      the open source library - but don&#39;t worry! We&#39;ll say it&#39;s a priority<br>      because our business depends on a fix!<br>    &lt;/Text&gt;<br>  &lt;/View&gt;<br>);<br><br>const Modals = createStackNavigator(<br>  {<br>    Navigator: {<br>      screen: Navigator,<br>    },<br>    Feedback: {<br>      screen: createStackNavigator({<br>        FeedbackForm: {<br>          screen: FeedbackForm,<br>          navigationOptions: ({ navigation }) =&gt; ({<br>            headerTitle: &#39;Feedback&#39;,<br>            headerRight: (<br>              &lt;Button title=&quot;Close&quot; onPress={() =&gt; navigation.pop()} /&gt;<br>            ),<br>          }),<br>        },<br>      }),<br>      navigationOptions: {<br>        gesturesEnabled: false,<br>      },<br>    },<br>  },<br>  {<br>    headerMode: &#39;none&#39;,<br>    mode: &#39;modal&#39;,<br>  }<br>);<br><br>export default createAppContainer(Modals);</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=33629431c0d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-react-native-log/best-practices-for-capturing-user-feedback-in-react-native-33629431c0d">Best Practices for Capturing User Feedback in React Native</a> was originally published in <a href="https://medium.com/the-react-native-log">The React Native Log</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Handle deep links in React Native apps]]></title>
            <link>https://medium.com/the-react-native-log/handle-deep-links-in-react-native-apps-b22055149b3a?source=rss----deee1de989f---4</link>
            <guid isPermaLink="false">https://medium.com/p/b22055149b3a</guid>
            <category><![CDATA[deep-linking]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Artsiom Staratsitarau]]></dc:creator>
            <pubDate>Mon, 15 Jan 2018 20:43:33 GMT</pubDate>
            <atom:updated>2019-10-27T11:40:30.726Z</atom:updated>
            <content:encoded><![CDATA[<h3>Understanding deep links</h3><p>In this post I would like to walk you through how to add a support of deep linking to your React Native application. I would like to tell you about a <a href="https://www.npmjs.com/package/react-native-deep-link"><strong>react-native-deep-link</strong></a>, a package written by me, created to reduce amount of code needed to implement this functionality. The package allows you to concentrate on writing application logic.</p><p>In this tutorial I am going to write a simple “Colors” application using <a href="https://www.npmjs.com/package/react-native-deep-link"><strong>react-native-deep-link</strong></a> package. The app will be able to handle incoming urls, containing the name of a color, and navigate a user to a screen of the corresponding color.</p><p>Before we start I would like to explain what deep linking is. Mobile app deep links (also known simply as “deep links”) point to content inside an app. It is useful sometimes to navigate user to a certain screen on app start rather than open a home screen. A general structure of a deep link is the following <strong><em>schemename://path?query_string</em></strong>. Scheme is an equivalent of a protocol in web. It is essential to choose a unique scheme name according to your brand to avoid conflicting schemes across different applications. Real deep links examples: <em>twitter://timeline</em>, <em>fb://profile.</em></p><p>In this application I will be using the next url format <strong><em>example://colors/&lt;color&gt;?textColor=&lt;text_color&gt;</em></strong>, where <em>color </em>and<strong> </strong><em>textColor </em>are parameters we will use to configure the appearance of a color screen, <strong><em>color </em></strong>sets a background color of the screen, <strong><em>textColor </em></strong>sets the color of the text with a color name at the center of the screen. I am going to write code for Android platform, but you can run the same code on iOS device, the difference will be shown in the configuration section.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/428/1*J1W3Xl37fbBGOw-CwciPXg.gif" /></figure><p>The final code is available <a href="https://github.com/Starotitorov/react-native-deep-link/tree/master/example"><strong>here</strong></a>.</p><h3>Implementing basic components</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/200/1*Iz8XQInb_NQNf_UDTdPGsg.gif" /></figure><p>First of all, we should create a new react-native project.</p><pre>react-native init example</pre><p>Then we need to install some packages.</p><pre>npm i --save redux react-redux react-navigation react-native-deep-link@0.0.3</pre><p>We will use react-navigation package to add navigation to our application. First of all, we need to add HomeScreen.js file to the project. It will be an initial screen of the application.</p><pre>// HomeScreen.js</pre><pre><strong>import </strong>React <strong>from </strong>&#39;react&#39;;<br><strong>import </strong>{ View, Text, StyleSheet } <strong>from </strong>&#39;react-native&#39;;<br><br><strong>export default function </strong>HomeScreen() {<br>    <strong>return </strong>(<br>        &lt;View style={styles.container}&gt;<br>            &lt;Text style={styles.text}&gt;<br>                Welcome to colors app!<br>            &lt;/Text&gt;<br>        &lt;/View&gt;<br>    );<br>}<br><br><strong>const </strong>styles = StyleSheet.create({<br>    container: {<br>        flex: 1,<br>        alignItems: &#39;stretch&#39;<br>    },<br>    text: {<br>        fontSize: 24,<br>        marginBottom: 18<br>    }<br>});</pre><p>In our application we want to have a support of deep linking. When we receive a url we want to navigate user to a separate screen with an appropriate background and text at the center of the screen. Let’s add this screen to our project, name this file ColorScreen.js.</p><pre>// ColorScreen.js</pre><pre><strong>import </strong>React, { Component } <strong>from </strong>&#39;react&#39;;<br><strong>import </strong>{ View, Text, StyleSheet } <strong>from </strong>&#39;react-native&#39;;<br><br><strong>const </strong>DEFAULT_BACKGROUND_COLOR = &#39;white&#39;;<br><strong>const </strong>DEFAULT_TEXT_COLOR = &#39;black&#39;;<br><br><strong>export default class </strong>ColorScreen <strong>extends </strong>Component {<br>    <strong>static </strong>navigationOptions = ({ navigation: { state: { params: { color } } } }) =&gt; {<br>        <strong>return </strong>{<br>            title: color<br>        }<br>    };<br><br>    render() {<br>        <strong>const </strong>{ navigation: { state: { params: { color, textColor }}}} = <strong>this</strong>.props;<br><br>        <strong>return </strong>(<br>            &lt;View style={[styles.container, { backgroundColor: color || DEFAULT_BACKGROUND_COLOR }]}&gt;<br>                &lt;Text style={[styles.text, { color: textColor || DEFAULT_TEXT_COLOR }]}&gt;<br>                    {color.toUpperCase()}<br>                &lt;/Text&gt;<br>            &lt;/View&gt;<br>        );<br>    }<br>}<br><br><strong>const </strong>styles = StyleSheet.create({<br>    container: {<br>        flex: 1,<br>        justifyContent: &#39;center&#39;,<br>        alignItems: &#39;center&#39;<br>    },<br>    text: {<br>        fontSize: 54<br>    }<br>});</pre><p>We will use navigation state parameters provided by react-navigation package to pass information about the color and text color to the screen.</p><pre>// ColorScreen.js</pre><pre>...<br><strong>const </strong>{ navigation: { state: { params: { color, textColor }}}} = <strong>this</strong>.props;<br>...</pre><p>So, now we have two screens and we want to add navigation to our project. We need to create a root navigator. Add AppNavigator.js file to the project.</p><pre>// AppNavigator.js</pre><pre><strong>import </strong>{ StackNavigator } <strong>from </strong>&#39;react-navigation&#39;;<br><strong>import </strong>HomeScreen <strong>from </strong>&#39;./HomeScreen&#39;;<br><strong>import </strong>ColorScreen <strong>from </strong>&#39;./ColorScreen&#39;;<br><br><strong>const </strong>AppNavigator = StackNavigator({<br>    Home: {<br>        screen: HomeScreen,<br>        navigationOptions: {<br>            title: &#39;Home&#39;<br>        }<br>    },<br>    Color: {<br>        screen: ColorScreen<br>    }<br>});<br><br><strong>export const </strong>AppRouter = AppNavigator.router;<br><strong>export default </strong>AppNavigator;</pre><p>We will add navigation state to redux store. Add reducer.js file to the project with the following code.</p><pre>// reducer.js</pre><pre><strong>import </strong>{ AppRouter } <strong>from </strong>&#39;./AppNavigator&#39;;<br><strong>import </strong>{ combineReducers } <strong>from </strong>&#39;redux&#39;;<br><br><strong>const </strong>initialState = AppRouter.getStateForAction(AppRouter.getActionForPathAndParams(&#39;Home&#39;));<br><br><strong>const </strong>navReducer = (state = initialState, action) =&gt; {<br>    <strong>const </strong>nextState = AppRouter.getStateForAction(action, state);<br><br>    <strong>return </strong>nextState || state;<br>};<br><br><strong>export default </strong>combineReducers({<br>    nav: navReducer<br>});</pre><p>We can use created navigator component in our project. Open App.js file created by react-native-cli and replace the content with the following code.</p><pre>// App.js</pre><pre><strong>import </strong>React <strong>from </strong>&#39;react&#39;;<br><strong>import </strong>{ addNavigationHelpers } <strong>from </strong>&#39;react-navigation&#39;;<br><strong>import </strong>{ connect } <strong>from </strong>&#39;react-redux&#39;;<br><strong>import </strong>AppNavigator <strong>from </strong>&#39;./AppNavigator&#39;;<br><br><strong>function </strong>App({ dispatch, nav }) {<br>    <strong>return </strong>(<br>        &lt;AppNavigator navigation={addNavigationHelpers({<br>            dispatch,<br>            state: nav<br>        })}/&gt;<br>    );<br>}<br><br><strong>const </strong>mapStateToProps = (state) =&gt; ({<br>    nav: state.nav<br>});<br><br><strong>export default </strong>connect(mapStateToProps)(App);</pre><p>We have added a reducer, but we have not created a Redux store for the application. Add the follwoing code to index.js file created by react-native-cli.</p><pre>// index.js</pre><pre><strong>import </strong>React <strong>from </strong>&#39;react&#39;;<br><strong>import </strong>{ AppRegistry } <strong>from </strong>&#39;react-native&#39;;<br><strong>import </strong>{ Provider } <strong>from </strong>&#39;react-redux&#39;;<br><strong>import </strong>{ createStore } <strong>from </strong>&#39;redux&#39;;<br><strong>import </strong>App <strong>from </strong>&#39;./App&#39;;<br><strong>import </strong>reducer <strong>from </strong>&#39;./reducer&#39;;<br><br><strong>const </strong>store = createStore(reducer);<br><br><strong>function </strong>Root() {<br>    <strong>return </strong>(<br>        &lt;Provider store={store}&gt;<br>            &lt;App /&gt;<br>        &lt;/Provider&gt;<br>    );<br>}<br><br>AppRegistry.registerComponent(&#39;example&#39;, () =&gt; Root);</pre><p>Now we can launch the application. But we have not added support of deep linking yet.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*5rK0Yu-tqEiyIjMggkVZTg.gif" /></figure><h3>Adding deep linking</h3><p>We are going to use <a href="https://www.npmjs.com/package/react-native-deep-link"><strong>react-native-deep-link</strong></a> package to add support of deep linking to the application.</p><p>But do not worry, it is extremely easy, the package will set everything up for us. All we need to do is import a <strong><em>createDeepLinkingHandler </em></strong>function from react-native-deep-link and pass an array of scheme configs to the function. The function will return a higher-order component, we will use it in our App component later. Add file with the following code to the application.</p><pre>// withDeepLinking.js</pre><pre><strong>import </strong>{ createDeepLinkingHandler } <strong>from </strong>&#39;react-native-deep-link&#39;;<br><strong>import </strong>{ NavigationActions } <strong>from </strong>&#39;react-navigation&#39;;<br><br><strong>const </strong>handleColorScreenDeepLink = ({ params: { color }, query: { textColor }}) =&gt; ({ dispatch }) =&gt; {<br>    dispatch(NavigationActions.navigate({<br>        routeName: &#39;Color&#39;,<br>        params: { color, textColor }<br>    }));<br>}<br><br><strong>export default </strong>withDeepLinking = createDeepLinkingHandler([{<br>    name: &#39;example:&#39;,<br>    routes: [{<br>        name: &#39;/colors/:color&#39;,<br>        callback: handleColorScreenDeepLink<br>    }]<br>}]);</pre><p><strong><em>createDeepLinkingHandler </em></strong>takes an array of objects. Each object should be a scheme config, which includes the name of scheme and array of route configs. Each route config has properties <strong><em>name </em></strong>and <strong><em>callback </em></strong>. Callback is a function which will be invoked in case of successful mapping of the deep link url to a route expression specified in property <strong><em>name</em></strong>. Route callback is a higher-order function which receives the result of url parsing and returns a function. This returned function receives component props. A result of url parsing is an object with the next set of properties:</p><pre>{<br>    scheme: &#39;example:&#39;,<br>    route: &#39;/colors/:color&#39;,<br>    query: {}, // Query string parameters<br>    params: {} // Url parameters<br>}</pre><p>In our application we defined one route <em>‘/colors/:color’ </em>and a callback to handle incoming urls. In this callback we receive <em>color </em>and <em>textColor </em>parameters using <em>params </em>and <em>query </em>provided by react-native-deep-link package.</p><p>So ,all we need to do now is to pass App component to withDeepLinking higher-order component.</p><pre>// App.js</pre><pre><strong>...<br>import </strong>withDeepLinking <strong>from </strong>&#39;./withDeepLinking&#39;;</pre><pre>...<br>// Definition of App component<br>...</pre><pre><strong>export default </strong>connect(mapStateToProps)(withDeepLinking(App));</pre><p>That is all. Now we take dispatch function provided by connect and pass it to the component returned from<em> withDeepLinking(App)</em>. The full code of App.js file.</p><pre>// App.js</pre><pre><strong>import </strong>React from &#39;react&#39;;<br><strong>import </strong>{ addNavigationHelpers } <strong>from </strong>&#39;react-navigation&#39;;<br><strong>import </strong>{ connect } <strong>from </strong>&#39;react-redux&#39;;<br><strong>import </strong>AppNavigator <strong>from </strong>&#39;./AppNavigator&#39;;<br><strong>import </strong>withDeepLinking <strong>from </strong>&#39;./withDeepLinking&#39;;<br><br><strong>function </strong>App({ dispatch, nav }) {<br>    <strong>return </strong>(<br>        &lt;AppNavigator navigation={addNavigationHelpers({<br>            dispatch,<br>            state: nav<br>        })}/&gt;<br>    );<br>}<br><br><strong>const </strong>mapStateToProps = (state) =&gt; ({<br>    nav: state.nav<br>});<br><br><strong>export default </strong>connect(mapStateToProps)(withDeepLinking(App));</pre><p>Now our application logic is implemented, all we need to do is configure the app.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*RFHrbyGvdricXMgUqviI2g.gif" /></figure><h3>Configuring Android</h3><p>Now when we have implemented deep linking we want to test the application. But before it we need to add some code to AndroidManifest.xml.</p><pre>&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;<br>          package=&quot;com.example&quot;<br>          android:versionCode=&quot;1&quot;<br>          android:versionName=&quot;1.0&quot;&gt;<br><br>    &lt;uses-permission android:name=&quot;android.permission.INTERNET&quot;/&gt;<br>    &lt;uses-permission android:name=&quot;android.permission.SYSTEM_ALERT_WINDOW&quot;/&gt;<br><br>    &lt;uses-sdk<br>            android:minSdkVersion=&quot;16&quot;<br>            android:targetSdkVersion=&quot;22&quot;/&gt;<br><br>    &lt;application<br>            android:name=&quot;.MainApplication&quot;<br>            android:allowBackup=&quot;true&quot;<br>            android:label=&quot;@string/app_name&quot;<br>            android:icon=&quot;@mipmap/ic_launcher&quot;<br>            android:theme=&quot;@style/AppTheme&quot;&gt;<br>        &lt;activity<br>                android:name=&quot;.MainActivity&quot;<br>                <strong>android:launchMode=&quot;singleTask&quot;</strong><br>                android:label=&quot;@string/app_name&quot;<br>                android:configChanges=&quot;keyboard|keyboardHidden|orientation|screenSize&quot;<br>                android:windowSoftInputMode=&quot;adjustResize&quot;&gt;<br>            &lt;intent-filter&gt;<br>                &lt;action android:name=&quot;android.intent.action.MAIN&quot;/&gt;<br>                &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot;/&gt;<br>            &lt;/intent-filter&gt;<br>            &lt;intent-filter android:label=&quot;filter_react_native&quot;&gt;<br>                &lt;action android:name=&quot;android.intent.action.VIEW&quot;/&gt;<br>                &lt;category android:name=&quot;android.intent.category.DEFAULT&quot;/&gt;<br>                &lt;category android:name=&quot;android.intent.category.BROWSABLE&quot;/&gt;<br>                <strong>&lt;data android:scheme=&quot;example&quot; android:host=&quot;colors&quot;/&gt;</strong><br>            &lt;/intent-filter&gt;<br>        &lt;/activity&gt;<br>        &lt;activity android:name=&quot;com.facebook.react.devsupport.DevSettingsActivity&quot;/&gt;<br>    &lt;/application&gt;<br><br>&lt;/manifest&gt;</pre><h3>Configuring iOS</h3><p>First of all, you need to register a URL scheme for your app in your Info.plist. After that you need to link RCTLinking to your project by following the steps described <a href="https://facebook.github.io/react-native/docs/linking-libraries-ios.html#manual-linking">here</a>. If you also want to listen to incoming app links during your app&#39;s execution, you&#39;ll need to add the following lines to your *AppDelegate.m:</p><pre>// iOS 9.x or newer<br>#import &lt;React/RCTLinkingManager.h&gt;</pre><pre>- (BOOL)application:(UIApplication *)application<br>   openURL:(NSURL *)url<br>   options:(NSDictionary&lt;UIApplicationOpenURLOptionsKey,id&gt; *)options<br>{<br>  return [RCTLinkingManager application:application openURL:url options:options];<br>}</pre><p>Save changes and run the application.</p><h3>Testing</h3><p>Now you can send urls to the application using the next command, which you can run in a terminal window.</p><p><strong>$ adb shell am start -W -a android.intent.action.VIEW -d “example://colors/green?textColor=red” com.example</strong></p><p>Let’s add the list of urls to the home screen of our application. We are going to use <em>Linking.openURL(url)</em> to open them.</p><pre>// HomeScreen.js</pre><pre><strong>import </strong>React <strong>from </strong>&#39;react&#39;;<br><strong>import </strong>{ View, Text, StyleSheet, FlatList, TouchableOpacity, Linking } <strong>from </strong>&#39;react-native&#39;;<br><br><strong>const </strong>URLS = [<br>    &#39;example://colors/green&#39;,<br>    &#39;example://colors/%23fff400&#39;,<br>    &#39;example://colors/green?textColor=red&#39;<br>];<br><br><strong>const </strong>ListItem = ({ url, onPressItem }) =&gt;<br>    &lt;TouchableOpacity<br>        style={styles.listItem}<br>        onPress={ () =&gt; onPressItem(url) }&gt;<br>        &lt;Text style={styles.listItemText}&gt;{ url }&lt;/Text&gt;<br>    &lt;/TouchableOpacity&gt;;<br><br><strong>export default function </strong>HomeScreen() {<br>    <strong>return </strong>(<br>        &lt;View style={styles.container}&gt;<br>            &lt;Text style={styles.text}&gt;<br>                Press one of the links below<br>            &lt;/Text&gt;<br>            &lt;FlatList<br>                data={ URLS }<br>                keyExtractor={(item, index) =&gt; index}<br>                renderItem={({ item }) =&gt;<br>                    &lt;ListItem onPressItem={ url =&gt; Linking.openURL(url) } url={ item } /&gt;<br>                }<br>            /&gt;<br>        &lt;/View&gt;<br>    );<br>}<br><br><strong>const </strong>styles = StyleSheet.create({<br>    container: {<br>        flex: 1,<br>        alignItems: &#39;stretch&#39;<br>    },<br>    text: {<br>        fontSize: 24,<br>        marginBottom: 18<br>    },<br>    listItem: {<br>        marginBottom: 8<br>    },<br>    listItemText: {<br>        textDecorationLine: &#39;underline&#39;<br>    }<br>});</pre><p>The final code of this example can be found <a href="https://github.com/Starotitorov/react-native-deep-link/tree/master/example"><strong>here</strong></a>.</p><p><strong>If you like the </strong><a href="https://www.npmjs.com/package/react-native-deep-link"><strong>react-native-deep-link</strong></a><strong> package, please star it on </strong><a href="https://github.com/Starotitorov/react-native-deep-link"><strong>github</strong></a><strong>!</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*Xm5SUqQHZibGgFdnPFfekg.jpeg" /></figure><p>Do not hesitate to open issues if you face problems using the package, create pull requests and help to improve the package.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b22055149b3a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-react-native-log/handle-deep-links-in-react-native-apps-b22055149b3a">Handle deep links in React Native apps</a> was originally published in <a href="https://medium.com/the-react-native-log">The React Native Log</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ Introducing Spotern App — Get Any Product You’ve Seen On TV with React Native!]]></title>
            <link>https://medium.com/the-react-native-log/introducing-spotern-app-get-any-product-youve-seen-on-tv-with-react-native-e4c6b5ea4604?source=rss----deee1de989f---4</link>
            <guid isPermaLink="false">https://medium.com/p/e4c6b5ea4604</guid>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Charles D. Mangwa]]></dc:creator>
            <pubDate>Thu, 21 Dec 2017 18:37:35 GMT</pubDate>
            <atom:updated>2018-03-15T20:19:29.344Z</atom:updated>
            <content:encoded><![CDATA[<h3>📺 Introducing Spotern App — Get Any Product You’ve Seen on TV with React Native!</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zOVmJRFm-oA8EPgLme6MPQ.png" /><figcaption>“Women’s clothes store” — <a href="https://unsplash.com/@hannahmorgan7">Hannah Morgan</a></figcaption></figure><p>2017 is coming to an end and I have one more thing to share with you! Something I’ve been working on for the past 10 months. Something I’m really proud of. Something I’ll be able to think about in 10 years and tell myself: “You did something great there, son”.</p><blockquote>🎉 Introducing <strong>Spotern: </strong>the app that helps you find all the products you’ve seen in movies, series, music clips and TV shows! 🍾</blockquote><h3>Project: Spotern 🔍</h3><p><a href="http://bit.ly/2swqZdh">Spotern</a> is a one-year old startup based in Paris, France. Its founder Nicolas got the idea while watching <a href="https://youtu.be/Do0AWVqPxas"><em>The Girl With The Dragon Tattoo</em></a><em>: </em>he really liked the jacket Daniel Craig was wearing in a scene, but didn’t know how or where to find it.</p><p>But wait. What if we could have a platform where we could <strong>find every single product</strong> that appears on screen? And if we don’t find it there: <strong>just ask the community</strong> to find it for us? Maybe <strong>gather some infos</strong> about an artist, a movie, a TV series, … in a single place? Well, that’s the 3 core elements of Spotern in a nutshell: <a href="http://bit.ly/2B52R5O"><strong>Spots</strong></a><strong>, </strong><a href="http://bit.ly/2iwwdyM"><strong>Wanted</strong></a><strong> &amp; </strong><a href="http://bit.ly/2ABpxHO"><strong>Medias</strong></a><strong>.</strong></p><p>The team quickly felt the need for a mobile app that could backup the already existing web app. This is where yours truly comes into play.</p><blockquote>My mission was to build a mobile app for our 50 000 contributors, on both iOS &amp; Android, using React Native.</blockquote><p>I used to work on small iOS-only projects, with other developers helping me, so this one was a big undertaking for me: being all by myself on a project of that scale.</p><p>So this post is not going to be particularly technical like my previous ones. This time, I’ll try to write a bit more about <em>how </em>I built things with React Native. I really want to focus here on the tools I used to build Spotern.</p><figure><a href="http://bit.ly/2swqZdh"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*viCEzkjw6DD5tMjle2zC8Q.png" /></a></figure><h3>Language: JavaScript ⚛️</h3><p>Spotern is one of those apps that would have been a living nightmare to build solely with native. We had around 30+ screens to implement and doing it twice for both iOS &amp; Android would have been really cumbersome. From there, React Native was probably the most obvious option. I’ve already written a post where I detail some benefits of this framework and (subjectively) compare it to its competitors, back in January.</p><p><a href="https://medium.com/the-react-native-log/tales-of-a-react-native-beginner-after-a-year-of-learning-7c72b2c51808">Tales of a React Native Beginner: After a Year Of Learning</a></p><h3>Navigation: React Router Navigation ⛵️</h3><p>This one also was a simple choice. I’ve been working for a few months with <a href="https://medium.com/u/3eff8cb59020">Léo Le Bras</a> on a new router for React Native that allows you to use <a href="https://reacttraining.com/react-router/">React Router</a> on mobile apps. Long story short: it’s <a href="https://medium.com/kalo-product-engineering/just-write-components-75bd7875223e">Just</a> <a href="https://twitter.com/ryanflorence/status/832466536820469760">Components</a>™. Components everywhere. Even if we consider it production ready, the router is still in its early age so its not perfect and everything, <a href="https://github.com/LeoLeBras/react-router-navigation/issues/54">but we’re working on it</a>. I had the opportunity to give a lightning talk about this during <a href="https://medium.com/u/1ed63648fd08">react-europe</a> 2016 (there’s also a full recap in a previous post, if you’re not really a video person):</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fd11dGHVVahk%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dd11dGHVVahk&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fd11dGHVVahk%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/784c055dc9526d85559904af024f4fc1/href">https://medium.com/media/784c055dc9526d85559904af024f4fc1/href</a></iframe><p><a href="https://medium.com/the-react-native-log/thousand-ways-to-navigate-in-react-native-f7a1e311a0e8">⛵Thousand Ways to Navigate in React Native</a></p><h3>Typing: Flow 🔮</h3><p>Here we have a subject that’s getting more and more popular in the JavaScript ecosystem: type checking. JavaScript relies on dynamic typing. Hower, for several REasons *winky face*, static typing is becoming a trend. Usually you’ll have 2 options to implement it: <a href="https://www.typescriptlang.org/">TypeScript</a> or <a href="https://flow.org/">FlowType</a>.</p><p>I personally opted for Flow because I found it easier to get started with (simply add a `/* @flow */` comment at the top of your .js file), much less obtrusive than TypeScript, it has a better type inference and it can be added gradually to your project file by file.</p><p>If you happened to be interested in type checking and want to take it to the next level: you might really be interested in <a href="https://reasonml.github.io/">ReasonML</a> 😏. Here is a great talk by <a href="https://medium.com/u/cd221e5efbe0">bloodyowl</a> that perfectly makes the link between the weaknesses of JavaScript (i.e.: its type system), and how ReasonML solves these problems and much more:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F-hfkny6hQNY%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D-hfkny6hQNY&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F-hfkny6hQNY%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/aac40e07fd1cd78508273f0cd4676392/href">https://medium.com/media/aac40e07fd1cd78508273f0cd4676392/href</a></iframe><h3>Time: date-fns ⏳</h3><p>Dates &amp; time are a core element of our app. Especially inside the blog section where articles &amp; categories are sorted by creation date. So: that’s something we don’t want to break, ever.</p><p>When we talk about date libraries in JavaScript, <a href="https://momentjs.com/">Moment.js</a> tends to be the most popular one. It has tons of features &amp; functionalities that lets you do basically anything with dates.</p><p>It was my go-to library for the past 2 years, but it has some limitations: mutability, a complex object-oriented API, bundle size, etc. That’s why I switched to <a href="https://date-fns.org/">date-fns</a> whose key features struck a chord with me: immutable &amp; pure, modular, ship with Flow &amp; TypeScript types and an incredibly simple API.</p><p>Instead of writing something like this:</p><pre>import moment from &#39;moment&#39;</pre><pre>const randomBirthday = moment(&quot;20171031&quot;, &quot;YYYYMMDD&quot;).fromNow();</pre><p>I’ll rather go with:</p><pre>import distanceToNow from &#39;date-fns/distance_in_words_to_now&#39;</pre><pre>const randomBirthday = distanceToNow(new Date(2017, 10, 31))</pre><h3>Analytics: Fabric 📊</h3><p>Tracking users’ interactions is a fundamental need of any app in production. After a little benchmark, I started with <a href="https://rnfirebase.io/docs/v3.1.*/getting-started">Firebase</a> which seemed to be the most convenient solution for analytics with React Native. Unfortunately, at some point I faced some conflicts between Firebase’ config, Google SignIn’s config and our back-end auth system.</p><p>As a result, I had to remove Firebase and find another solution, which was: Fabric. After being acquired from Twitter by Google back in January 2017, Fabric evolved a lot to become the great tool we have now.</p><p>Our marketing team is really happy with the result of this switch: segmentation has never been that easy to configure and visualize, events and categories are pretty simple to generate &amp; track, and the #1 selling point: weekly reports come with emojis!👌 They are so happy with it they are even talking about “also switching the web app analytics system over Fabric”. 😄</p><h3>Data: React Data Fetching 🎣</h3><p>Data fetching. That’s probably the core element of any application. I’ve been doing it in a variety of ways in the past but today, I might have found something I really like.</p><p>Keeping the <em>Just Components™</em> state of mind I’ve been using with React Router Navigation, I’ve built a component that fetches data. I find this way of fetching data so convenient that I extracted this component from our codebase, to open source as a standalone library: react-data-fetcher 🎉</p><blockquote>A component-driven way to fetch data in React!</blockquote><p>This library will probably get its own Medium post when it’ll hit npm, because that’s something I’ve been thinking about for a long time and it’s worth it. I’m still polishing the final details before publishing it, but here is a little glimpse of what you’ll be able to do… 👀</p><pre>&lt;Fetch<br>  path={`${API}/${category}/featuredArticles`}<br>  params={{<br>    method: ‘POST’,<br>    body: {<br>    language: ‘en’,<br>     start: 0,<br>     limit: this.state.limit,<br>     categoryID,<br>    },<br>  }}<br>  refetch={<em>this</em>.state.isRefreshing}<br>  onLoading={this._renderLoadingModal}<br>  onFetch={<em>this</em>._saveData}<br>  onError={this._renderErrorModal}<br>/&gt;</pre><blockquote>EDIT 03/15/2018: I just published it!</blockquote><p><a href="https://medium.com/@CharlesMangwa/introducing-react-data-fetching-2140a1d36cc8">Introducing React Data Fetching 🎣</a></p><h3>Starter: React Native Simple Kit 🚀</h3><p>When you start working on a React Native project, your first reflex could be to use tools like <a href="https://expo.io/">Expo</a> or <a href="https://facebook.github.io/react-native/blog/2017/03/13/introducing-create-react-native-app.html">create-react-native-app</a>. They work well with iOS and Android, they’re backed by a great community, and are always up-to-date with React Native.</p><p>However, there are some apps like Spotern that need something a bit more complex. And as we saw earlier, I’ve already been using a lot of custom tools. So while working on this app, I felt the need for a handcrafted starter kit that could help me with my future projects. That’s why I’m thrilled to introduce another open source project that comes from my work at Spotern: <br><a href="https://github.com/CharlesMangwa/react-native-simple-kit/">react-native-simple-kit</a> 🎉.</p><blockquote>Get started with React Native and Redux with no effort!</blockquote><p>I’ll let you discover the boilerplate in the <a href="https://github.com/CharlesMangwa/react-native-simple-kit">README.md</a> but the idea is to have right out of the box, a starter with all the components, helpers, unit tests, project structure, Redux &amp; ESLint configs I need for any React Native app I could possibly be working on. This boilerplate represents pretty well <em>how </em>I usually build my apps now. Let me know what you think about it!</p><figure><a href="http://bit.ly/2swqZdh"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FJd5TDjpM68wTSRozcZSyg.jpeg" /></a></figure><p>That’s all folks! Spotern is now available on both iOS and Android: dont hesitate to give it a try and give me your feedback! Feel free to contact me here or on Twitter <a href="https://twitter.com/@Charles_Mangwa">@Charles_Mangwa</a> to share your thoughts about the article and the app. Anyhow I’ll hope you’ll like what you’ll see!</p><ul><li><a href="https://play.google.com/store/apps/details?id=com.spotern">Spotern - Watch It, Get It - Android Apps on Google Play</a></li><li><a href="https://itunes.apple.com/us/app/spotern-watch-it-get-it/id1269594635">Spotern - Watch It, Get It on the App Store</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e4c6b5ea4604" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-react-native-log/introducing-spotern-app-get-any-product-youve-seen-on-tv-with-react-native-e4c6b5ea4604">📺 Introducing Spotern App — Get Any Product You’ve Seen On TV with React Native!</a> was originally published in <a href="https://medium.com/the-react-native-log">The React Native Log</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Hire React Native Developers & Find React Native jobs]]></title>
            <link>https://medium.com/the-react-native-log/how-to-hire-react-native-developers-find-react-native-jobs-6c781aaffe01?source=rss----deee1de989f---4</link>
            <guid isPermaLink="false">https://medium.com/p/6c781aaffe01</guid>
            <category><![CDATA[jobs]]></category>
            <category><![CDATA[hiring]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[development]]></category>
            <dc:creator><![CDATA[Spencer Carli]]></dc:creator>
            <pubDate>Mon, 18 Sep 2017 18:41:19 GMT</pubDate>
            <atom:updated>2017-09-18T18:22:32.135Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*W2QPjYo1g13iMAG36_VdEQ.jpeg" /></figure><p>Introducing the easiest way to find React Native developers &amp; get hired as a React Native developer.</p><p>At <a href="http://learn.handlebarlabs.com/">Handlebar Labs</a> I train people to become React Native developers. Part of that training is exchanging emails with the students to help them through any of the material. Once someone has worked through a course one of the most common questions I receive is</p><blockquote>Do you know of any companies looking to hire React Native developers?</blockquote><p>And I do! Because another question I often receive is</p><blockquote>Do you know of any developers looking for React Native work?</blockquote><p>I get at least a dozen of these emails per week and I try my best to link up developers and companies but I inevitably miss some (probably a lot). I want to reduce the number of <a href="http://gph.is/13t5ktX">missed connections</a> that could have resulted in great working relationships because of me.</p><p>That’s why I put together <a href="https://www.workreactnative.com/"><em>Work React Native</em></a> last night.</p><p><a href="https://www.workreactnative.com/">Work React Native</a></p><p>It’s a simple &amp; free service to connect developers with companies.</p><h4>I’m a developer looking for React Native work</h4><p>Sign up for the email list and every Monday I’ll send you a list of positions added that week. Each position will have a position title, position description, and link to get in touch with the person/company. That’s it.</p><h4>I’m a company looking for a React Native developer</h4><p>Fill out the Google form with the required info (title, short description, and url to reach you) and your position will be sent out the following Monday. If you don’t find the right developer that week fill out the form again and it will be shared again.</p><p>That’s it. Nothing fancy. Completely free. I put it together to help people find work, reduce my email volume (I’m already slow to reply), and help reduce the email volume of others who receive similar questions.</p><p>I hope it will help you find some React Native work/developers! If you think it will benefit someone else be sure to recommend/clap for this article &amp; share it to increase visibility.</p><p>👋</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6c781aaffe01" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-react-native-log/how-to-hire-react-native-developers-find-react-native-jobs-6c781aaffe01">How to Hire React Native Developers &amp; Find React Native jobs</a> was originally published in <a href="https://medium.com/the-react-native-log">The React Native Log</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[React Native Basics: Copy to Clipboard]]></title>
            <link>https://medium.com/the-react-native-log/react-native-basics-copy-to-clipboard-86023cda4175?source=rss----deee1de989f---4</link>
            <guid isPermaLink="false">https://medium.com/p/86023cda4175</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[development]]></category>
            <dc:creator><![CDATA[Spencer Carli]]></dc:creator>
            <pubDate>Tue, 29 Aug 2017 18:43:35 GMT</pubDate>
            <atom:updated>2017-08-29T21:04:57.018Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*o9hs6NDoW00wc7nZirjGzQ.png" /></figure><p>Reading and writing from the clipboard is incredibly easy in React Native by using the <a href="https://facebook.github.io/react-native/docs/clipboard.html">Clipboard</a> API. In this quick tutorial we’ll build a simple app to read and write to it.</p><h3>Starting App</h3><p>To keep this tutorial simple we’ll start with a very basic app. It’s got two buttons, a TextInput, and some areas to render text.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/422/1*PfUWSbhAhzvwxjDGvsqzPA.png" /><figcaption>The basic app</figcaption></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/92cfb150dd8435c4b27c2120c8b24cbb/href">https://medium.com/media/92cfb150dd8435c4b27c2120c8b24cbb/href</a></iframe><h3>Reading from the Clipboard</h3><p>Let’s say you want to copy a password from the user’s clipboard — unless that text is going into an input the user can’t press and hold to copy it so we want to give them a simple button to copy it instead.</p><p>That’s where Clipboard.getString() comes in. This function returns a promise with either the value or an error.</p><p>First, make sure you import { Clipboard } from &#39;react-native&#39;;.</p><p>You can handle promises a few different ways but I’ll be opting to use async/await because it keeps are code very succinct.</p><p>Everything is already wired up (the button press will call the readFromClipboard function) so we can just focus on interacting with the Clipboard API.</p><p>Since we’re using async/await we need to put async in front of our function.</p><pre>readFromClipboard = async () =&gt; {<br>  alert(&#39;TODO: Read from Clipboard&#39;); <br>};</pre><p>Then inside that function we’ll get the clipboard value and save it to state. Since getString is a promise we need to wait for that value, which we can do by using the await keyword.</p><pre>readFromClipboard = async () =&gt; {   <br>  const clipboardContent = await Clipboard.getString();   <br>  this.setState({ clipboardContent }); <br>};</pre><p>That will then display the contents of the keyboard below “Clipboard Contents:”!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/371/1*pmlLoqvBUMnBADSd5sbWOg.gif" /><figcaption>Reading data from clipboard</figcaption></figure><p>Try copying a contact’s name and the pasting it in the app.</p><h3>Writing to the Clipboard</h3><p>Writing to the clipboard is almost exactly the same so I’ll keep this one more brief. Once we successfully write to the clipboard we’ll alert that we did so to the user.</p><blockquote><em>Note: The user could just as easily copy the value directly from the input, but where’s the fun in that?</em></blockquote><p>First, make the function work with the await keyboard by putting async in front of it.</p><pre>writeToClipboard = async () =&gt; {   <br>  alert(&#39;TODO: Write to the Clipboard&#39;); <br>};</pre><p>We then want to write the value in our input to the clipboard and alert the user once it’s completed.</p><pre>writeToClipboard = async () =&gt; {<br>  await Clipboard.setString(this.state.text);<br>  alert(&#39;Copied to Clipboard!&#39;);<br>};</pre><p>Go ahead and copy something from your app, paste it into another app, or copy it to the clipboard and then read it from the code we wrote in the previous section!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/371/1*9-UgspMbarLeR1KI-WmC6g.gif" /><figcaption>Writing data from clipboard</figcaption></figure><p>And there we go! It’s a <em>very</em> simple API to work with but sometimes an example helps.</p><blockquote><em>If you’re interested in learning other pieces of React Native — such as component design, navigation, redux, redux sagas, and more — check out </em><a href="http://reactnativebasics.com/"><em>my free course</em></a><em>! It’ll save you a ton of time.</em></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=86023cda4175" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-react-native-log/react-native-basics-copy-to-clipboard-86023cda4175">React Native Basics: Copy to Clipboard</a> was originally published in <a href="https://medium.com/the-react-native-log">The React Native Log</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>