<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Vishal Narkhede</title>
    <description>The latest articles on Forem by Vishal Narkhede (@vishalnarkhede).</description>
    <link>https://forem.com/vishalnarkhede</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F327867%2F8b8d5ad5-3f6c-468e-b6e4-2917d175e105.png</url>
      <title>Forem: Vishal Narkhede</title>
      <link>https://forem.com/vishalnarkhede</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/vishalnarkhede"/>
    <language>en</language>
    <item>
      <title>React Native: How To Build  Bidirectional Infinite Scroll</title>
      <dc:creator>Vishal Narkhede</dc:creator>
      <pubDate>Mon, 01 Mar 2021 15:50:13 +0000</pubDate>
      <link>https://forem.com/vishalnarkhede/react-native-how-to-build-bidirectional-infinite-scroll-32ph</link>
      <guid>https://forem.com/vishalnarkhede/react-native-how-to-build-bidirectional-infinite-scroll-32ph</guid>
      <description>&lt;h2&gt;
  
  
  👋 Introduction
&lt;/h2&gt;

&lt;p&gt;​&lt;br&gt;
There have been many discussions on Stack Overflow and GitHub around implementing infinite scroll using React Native, on top of &lt;code&gt;FlatList&lt;/code&gt; or &lt;code&gt;SectionList&lt;/code&gt;. I've found that there aren't any easy solutions out there for bidirectional infinite scroll, which works on both Android and iOS. Recently, while working on &lt;code&gt;v3.0.0&lt;/code&gt; of &lt;a href="https://github.com/GetStream/stream-chat-react-native" rel="noopener noreferrer"&gt;React Native Chat SDK&lt;/a&gt; at &lt;a href="https://getstream.io/" rel="noopener noreferrer"&gt;Stream&lt;/a&gt;, we added bidirectional infinite scroll to our chat components. We had to jump through plenty of hurdles to make it happen while maintaining a good user experience around scrolling (especially for Android). Thus we decided to publish an excellent and small open-source package, on top of &lt;code&gt;FlatList&lt;/code&gt;, to make this task easier for other React Native developers.​&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub ⭐ :&lt;/strong&gt; &lt;a href="https://github.com/GetStream/react-native-bidirectional-infinite-scroll" rel="noopener noreferrer"&gt;github.com/getstream/react-native-bidirectional-infinite-scroll&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;​&lt;/p&gt;
&lt;h3&gt;
  
  
  🔌 Usage
&lt;/h3&gt;

&lt;p&gt;As mentioned earlier, this package is a wrapper around FlatList, and so it can be used exactly like FlatList from React Native, with few additional props:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feuj48dje72sea9ps3nn3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feuj48dje72sea9ps3nn3.png" alt="Usage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;​&lt;/p&gt;
&lt;h3&gt;
  
  
  🔮 Quick Preview
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Scroll down further, for the tutorial&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;iOS&lt;/th&gt;
&lt;th&gt;Android&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fc0771f9436c1c694f15b6aa3b4115c99%2Fdvg7qhro5044qfvqn3v8.gif" alt="Alt Text"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F5474d3098fc7fef405dd55b4da36c9a9%2Ftae5gh1l0aopprx4uyh4.gif" alt="Alt Text"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  ​
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Let's Dive Deep
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What and How?&lt;/li&gt;
&lt;li&gt;Tutorial: Chat UI With Bidirectional Infinite Scroll&lt;/li&gt;
&lt;li&gt;What's more?!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;​​​&lt;/p&gt;
&lt;h2&gt;
  
  
  📚 What and How
&lt;/h2&gt;

&lt;p&gt;This section will walk you through the hurdles of implementing bidirectional infinite scroll and how we solved them.&lt;br&gt;
​&lt;/p&gt;
&lt;h3&gt;
  
  
  Support for &lt;code&gt;onStartReached&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://reactnative.dev/docs/flatlist" rel="noopener noreferrer"&gt;FlatList&lt;/a&gt; from React Native has built-in support for infinite scroll in a single direction (from the end of the list). You can add a prop &lt;code&gt;onEndReached&lt;/code&gt;on &lt;code&gt;FlatList&lt;/code&gt;. This function gets called when your scroll is near the end of the list, and thus you can append more items to the list from this function. You can Google for &lt;strong&gt;React Native infinite scrolling&lt;/strong&gt;, and you will find plenty of examples for this. Unfortunately, the &lt;code&gt;FlatList&lt;/code&gt; doesn't provide any similar prop for &lt;code&gt;onStartReached&lt;/code&gt; for infinite scrolling in other directions.&lt;br&gt;
​&lt;br&gt;
We have added support for this prop as part of this package by simply adding the &lt;code&gt;onScroll&lt;/code&gt; handler on &lt;code&gt;FlatList&lt;/code&gt;, and executing the callback function (&lt;code&gt;onStartReached&lt;/code&gt;) when the scroll is near the start of the list. If you take a look at the implementation of &lt;a href="https://github.com/facebook/react-native/blob/master/Libraries/Lists/VirtualizedList.js" rel="noopener noreferrer"&gt;VirtualizedList&lt;/a&gt;, you will notice that &lt;code&gt;onEndReached&lt;/code&gt;function gets called only once per content length. That's there for a good purpose - to avoid redundant function calls on every scroll position change. Similar optimizations have been done for &lt;code&gt;onStartReached&lt;/code&gt; within this package.&lt;br&gt;
​&lt;/p&gt;
&lt;h3&gt;
  
  
  Race condition between &lt;code&gt;onStartReached&lt;/code&gt; and &lt;code&gt;onEndReached&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;To maintain a smooth scrolling experience, we need to manage the execution order of &lt;code&gt;onStartReached&lt;/code&gt; and &lt;code&gt;onEndReached&lt;/code&gt;. Because if both the callbacks happen at (almost) the same time, which means items will be added to the list from both directions. This may result in scroll jump, and that's not a good user experience. Thus it's essential to make sure one callback waits for the other callback to finish.&lt;br&gt;
​&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;onStartReachedThreshold&lt;/code&gt; and &lt;code&gt;onEndReachedThreshold&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;FlatList&lt;/code&gt; from React Native has a support for the prop &lt;code&gt;onEndReachedThreshold&lt;/code&gt;, which is &lt;a href="https://reactnative.dev/docs/flatlist#onendreachedthreshold" rel="noopener noreferrer"&gt;documented here&lt;/a&gt;&lt;br&gt;
​&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How far from the end (in units of visible length of the list) the bottom edge of the list must be from the end of the content to trigger the &lt;code&gt;onEndReached&lt;/code&gt; callback.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, it's easier to have a fixed value offset (distance from the end of the list) to trigger one of these callbacks. Thus we can maintain these two values within our implementation. So &lt;code&gt;onStartReachedThreshold&lt;/code&gt; and &lt;code&gt;onEndReachedThreshold&lt;/code&gt; props accept the number - distance from the end of the list to trigger one of these callbacks.&lt;br&gt;
​&lt;/p&gt;
&lt;h3&gt;
  
  
  Smooth scrolling experience
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;FlatList&lt;/code&gt; from React Native accepts a prop - &lt;a href="https://reactnative.dev/docs/scrollview#maintainvisiblecontentposition" rel="noopener noreferrer"&gt;maintainVisibleContentPosition&lt;/a&gt;, which makes sure your scroll doesn't jump to the end of the list when more items are added to the list. But this prop is only supported on iOS for now. So taking some inspiration from this &lt;a href="https://github.com/facebook/react-native/pull/29466" rel="noopener noreferrer"&gt;PR&lt;/a&gt;, we published our separate package to add support for this prop on Android - &lt;a href="https://github.com/GetStream/flat-list-mvcp#maintainvisiblecontentposition-prop-support-for-android-react-native" rel="noopener noreferrer"&gt;flat-list-mvcp&lt;/a&gt;. And thus &lt;code&gt;@stream-io/flat-list-mvcp&lt;/code&gt; is a dependency of the &lt;code&gt;react-native-bidirectional-scroll&lt;/code&gt; package.&lt;br&gt;
​&lt;/p&gt;
&lt;h2&gt;
  
  
  🖥 Tutorial: Chat UI With Bidirectional Infinite Scroll
&lt;/h2&gt;

&lt;p&gt;Now let's see how we can implement a chat message list, scrolling infinitely in both directions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;Let's start by creating a React Native app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx react-native init AwesomeChatList
$ cd AwesomeChatList
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;​&lt;br&gt;
Add the required dependencies:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ yarn add react-native-bidirectional-infinite-scroll @stream-io/flat-list-mvcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next, run the app:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx react-native run-ios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Note: The server will auto-refresh as you make changes to the code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;​&lt;/p&gt;
&lt;h3&gt;
  
  
  Create message list
&lt;/h3&gt;

&lt;p&gt;Open this project in some editor (I love VS Code) and open &lt;code&gt;App.js&lt;/code&gt; in the project's root directory.&lt;br&gt;
​&lt;br&gt;
We are going to populate the list with dummy messages. In a real application, these messages are queried against a server. For example, we can write a simple utility function to mock this API call for querying &lt;code&gt;n&lt;/code&gt; number of messages.&lt;br&gt;
​&lt;br&gt;
Create a file - &lt;code&gt;utils.js&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Next, let's write a small UI component for the message bubble. Create a file named &lt;code&gt;MessageBubble.js&lt;/code&gt;.​&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
​&lt;br&gt;
Now let's first implement a simple list, which renders these messages on the first load. Copy the following content to &lt;code&gt;App.js&lt;/code&gt; and hit save.


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You should be able to see the list of messages as shown in the screenshot on the right.&lt;br&gt;
​&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F546da9ee13625ce4f5ebba16747e50a0%2F0coucxr19ywzwftsicgq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F546da9ee13625ce4f5ebba16747e50a0%2F0coucxr19ywzwftsicgq.png" alt="Message List"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Add Infinite Scroll
&lt;/h3&gt;

&lt;p&gt;Next, let's implement infinite scroll to the list by adding &lt;code&gt;onStartReached&lt;/code&gt; and &lt;code&gt;onEndReached&lt;/code&gt; prop functions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;onStartReached&lt;/code&gt; - add 10 messages at the beginning of the list&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onEndReached&lt;/code&gt; - add 10 messages at the end of the list
​&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replace the contents of &lt;code&gt;App.js&lt;/code&gt; with the following:&lt;br&gt;
​&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And that's it. If you scroll up or down, you will see new messages being loaded in the list and scroll position being maintained as well (both for Android and iOS)&lt;br&gt;
​&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fc6394ba8863774747d8bb552e28200ad%2Fdvg7qhro5044qfvqn3v8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fc6394ba8863774747d8bb552e28200ad%2Fdvg7qhro5044qfvqn3v8.gif" alt="Bidirectional Infinite Scroll"&gt;&lt;/a&gt;&lt;br&gt;
​&lt;/p&gt;
&lt;h3&gt;
  
  
  Send Message
&lt;/h3&gt;

&lt;p&gt;In real chat applications, you don't actually "infinitely" scroll. There is always an end to the &lt;code&gt;loadMoreRecentMessages&lt;/code&gt; function. And after this point, you will want the scroll to automatically move to the bottom of the list, as other users send a new message or if you send a new message.&lt;br&gt;
​&lt;br&gt;
Basically, after this point, we want to enable the "autoscroll to top" (bottom in our case, since the list is inverted) functionality of &lt;code&gt;FlatList&lt;/code&gt;. You can do this by setting a prop &lt;code&gt;enableAutoscrollToTop&lt;/code&gt; as &lt;code&gt;true&lt;/code&gt;. Additionally, you can also set &lt;code&gt;autoscrollToTopThreshold&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;.&lt;br&gt;
​&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's try to simulate this scenario by keeping a counter on the number of times recent messages were queried. Once the counter crosses 2, let's stop querying the message.
​&lt;/li&gt;
&lt;li&gt;Let's add a "Send Message" button at the bottom to send a single message.
​&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replace the contents of &lt;code&gt;App.js&lt;/code&gt; with following&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now scroll to the bottom couple of times, until you can't load any more recent messages. Now try to send a single message by pressing the "Send Message" button. You will see scroll automatically scrolling to the bottom of the list. But if you scroll up a bit and then send a message - then the scroll position will be maintained. The &lt;code&gt;autoscrollToTopThreshold&lt;/code&gt; prop controls this threshold.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3wdzvxpcdabfeuv98nvn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3wdzvxpcdabfeuv98nvn.gif" alt="Send Message"&gt;&lt;/a&gt;&lt;br&gt;
​&lt;/p&gt;

&lt;h2&gt;
  
  
  🎉 Congratulations!! Whats more?!
&lt;/h2&gt;

&lt;p&gt;You've implemented a bidirectional infinite scroll with React Native! Additionally following props are available to add more customisations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;activityIndicatorColor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;enableAutoscrollToTop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;autoscrollToTopThreshold&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onStartReachedThreshold&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onEndReachedThreshold&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;showDefaultLoadingIndicators&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HeaderLoadingIndicator&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FooterLoadingIndicator&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you found it useful. Feel free to add some questions, comments, and feedback here. And don't forget to put a ⭐ on &lt;a href="https://github.com/GetStream/react-native-bidirectional-infinite-scroll" rel="noopener noreferrer"&gt;github repo&lt;/a&gt;. Happy Coding!!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>infinitescroll</category>
      <category>opensource</category>
    </item>
    <item>
      <title>maintainVisibleContentPosition prop for Android react-native</title>
      <dc:creator>Vishal Narkhede</dc:creator>
      <pubDate>Wed, 09 Dec 2020 21:27:35 +0000</pubDate>
      <link>https://forem.com/vishalnarkhede/maintainvisiblecontentposition-prop-for-android-react-native-3olf</link>
      <guid>https://forem.com/vishalnarkhede/maintainvisiblecontentposition-prop-for-android-react-native-3olf</guid>
      <description>&lt;p&gt;In react-native, &lt;a href="https://reactnative.dev/docs/scrollview"&gt;ScrollView&lt;/a&gt; (and &lt;a href="https://reactnative.dev/docs/flatlist"&gt;FlatList&lt;/a&gt;) component have support for a prop &lt;a href="https://reactnative.dev/docs/scrollview#maintainvisiblecontentposition"&gt;&lt;code&gt;maintainVisibleContentPosition&lt;/code&gt;&lt;/a&gt;, which is really useful for chat-like applications where you want to see new messages scroll into place. Also you might need it in other applications where you need bi-directional infinite scroll. Although this prop is  only supported on iOS for ScrollView/FlatList. &lt;/p&gt;

&lt;p&gt;But it's easy enough to get it working Android by a simple wrapper. We at &lt;a href="https://getstream.io/"&gt;Stream&lt;/a&gt; built this wrapper for our in-house &lt;a href="https://github.com/GetStream/stream-chat-react-native"&gt;react-native chat sdk&lt;/a&gt;, but we are making it public, in case it helps other devs from react-native community.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NPM - &lt;a href="https://www.npmjs.com/package/@stream-io/flat-list-mvcp"&gt;https://www.npmjs.com/package/@stream-io/flat-list-mvcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Github - &lt;a href="https://github.com/GetStream/flat-list-mvcp"&gt;https://github.com/GetStream/flat-list-mvcp&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @stream-io/flat-list-mvcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FlatList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ScrollView&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stream-io/flat-list-mvcp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlatList&lt;/span&gt;
    &lt;span class="nx"&gt;maintainVisibleContentPosition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
        &lt;span class="na"&gt;autoscrollToTopThreshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;minIndexForVisible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ScrollView&lt;/span&gt;
    &lt;span class="nx"&gt;maintainVisibleContentPosition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
        &lt;span class="na"&gt;autoscrollToTopThreshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;minIndexForVisible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cheers and happy coding :)&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href="https://github.com/stackia"&gt;stackia&lt;/a&gt; for &lt;a href="https://github.com/facebook/react-native/pull/29466#issuecomment-664367382"&gt;this&lt;/a&gt; :)&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>android</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Tutorial: How to Build a Slack Clone with React Native — Part 3</title>
      <dc:creator>Vishal Narkhede</dc:creator>
      <pubDate>Tue, 17 Nov 2020 16:06:03 +0000</pubDate>
      <link>https://forem.com/vishalnarkhede/tutorial-how-to-build-a-slack-clone-with-react-native-part-3-554m</link>
      <guid>https://forem.com/vishalnarkhede/tutorial-how-to-build-a-slack-clone-with-react-native-part-3-554m</guid>
      <description>&lt;p&gt;In &lt;a href="https://getstream.io/blog/slack-clone-with-stream-chat-part-2/" rel="noopener noreferrer"&gt;Part 2&lt;/a&gt; of this tutorial, we covered how to build Slack-like navigation, channel list screen, channel screen, reaction picker, and action sheet. In this tutorial, Part 3, we will build various search screens and thread screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources 👇
&lt;/h2&gt;

&lt;p&gt;Below are a few helpful links if you get stuck along the way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-react-native" rel="noopener noreferrer"&gt;Official Slack Clone Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-expo" rel="noopener noreferrer"&gt;Official Slack Clone Repo for Expo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactnavigation.org/" rel="noopener noreferrer"&gt;Documentation for React Navigation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/stream-chat-react-native" rel="noopener noreferrer"&gt;Stream Chat Component Library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Thread Screen
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;MessageList&lt;/code&gt; component accepts the prop function &lt;code&gt;onThreadSelect&lt;/code&gt;, which is attached to the &lt;a href="https://github.com/GetStream/stream-chat-react-native/blob/master/src/components/Message/MessageSimple/MessageContent.tsx#L260" rel="noopener noreferrer"&gt;onPress handler&lt;/a&gt; for reply count text below the message bubble. If you check our &lt;code&gt;ChannelScreen&lt;/code&gt; component, you will see navigation logic to &lt;code&gt;ThreadScreen&lt;/code&gt; added to the &lt;code&gt;onThreadSelect&lt;/code&gt; prop on the &lt;code&gt;MesaageList&lt;/code&gt; component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/GetStream/stream-chat-react-native/blob/master/src/components/Thread/Thread.tsx" rel="noopener noreferrer"&gt;&lt;code&gt;Thread&lt;/code&gt;&lt;/a&gt; is provided out-of-the-box from &lt;code&gt;stream-chat-react-native&lt;/code&gt;. If you look at the source code, it's a set of &lt;code&gt;Message&lt;/code&gt; (parent message bubble), &lt;code&gt;MessageList&lt;/code&gt;, and a &lt;code&gt;MessageInput&lt;/code&gt; component. You can customize these underlying components using props – &lt;code&gt;additionalParentMessageProps&lt;/code&gt;, &lt;code&gt;additionalMessageListProps&lt;/code&gt; and &lt;code&gt;additionalMessageInputProps&lt;/code&gt;. We can use this Thread component easily for our purpose.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We need to implement a checkbox labeled "Also send to {channel_name}" (as shown in the screenshot below). When ticked, the message should appear on the channel as well. We can use &lt;code&gt;show_in_channel&lt;/code&gt; property on the message object for this, as mentioned in docs for &lt;a href="https://getstream.io/chat/docs/threads/?language=js" rel="noopener noreferrer"&gt;threads and replies&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If you specify &lt;code&gt;show_in_channel&lt;/code&gt;, the message will be visible both in a thread of replies and the main channel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F73910013f424a774f1154b9ca7692f08%2FScreenshot-2020-11-04-at-11-44-16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F73910013f424a774f1154b9ca7692f08%2FScreenshot-2020-11-04-at-11-44-16.png" alt="Thread Reply in the Channel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the checkbox is ticked, add &lt;code&gt;show_in_channel: true&lt;/code&gt; to the message object before sending it. We can achieve this by providing a &lt;code&gt;doSendMessageRequest&lt;/code&gt; prop function, which overrides Channel components default sendMessage handler.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F02cf0ddb76529ca4d9ef85ccf1c4aafb%2Finputboxthread.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F02cf0ddb76529ca4d9ef85ccf1c4aafb%2Finputboxthread.gif" alt="Input box for thread"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use the &lt;a href="https://reactnative.dev/docs/animated" rel="noopener noreferrer"&gt;Animated API&lt;/a&gt; by React Native to achieve the sliding animation of the checkbox and other action buttons.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now assign the &lt;code&gt;ThreadScreen&lt;/code&gt; component to its respective &lt;code&gt;HomeStack.Screen&lt;/code&gt; in &lt;code&gt;App.js&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Search Screens
&lt;/h2&gt;

&lt;p&gt;There are four modal search screens that we are going to implement in this tutorial:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F058210eff54bc0a461169548608987f6%2FScreenshot-2020-11-03-at-07-40-09.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F058210eff54bc0a461169548608987f6%2FScreenshot-2020-11-03-at-07-40-09.png" alt="Slack Clone Layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Jump to Channel Screen &amp;amp; Channel Search Screen
&lt;/h3&gt;

&lt;p&gt;We can create a standard component for Jump to channel screen and Channel search screen.&lt;/p&gt;

&lt;p&gt;Let's first create a common component needed across the search screens.&lt;/p&gt;

&lt;h3&gt;
  
  
  Direct Messaging Avatar
&lt;/h3&gt;

&lt;p&gt;This is a component for the avatar of direct messaging conversation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For one to one conversations, it shows other member's picture with his presence indicator&lt;/li&gt;
&lt;li&gt;For group conversation, it shows stacked avatars of two of its members.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fd1f56140939b3464f518f32be556a1a2%2FMedium-article-01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fd1f56140939b3464f518f32be556a1a2%2FMedium-article-01.png" alt="Status Indicators"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Modal Screen Header
&lt;/h3&gt;

&lt;p&gt;This is a common header for modal screens, with a close button on the left and title in the center.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now let's build a &lt;code&gt;ChannelSearchScreen&lt;/code&gt;, which can be used as "Jump to channel screen" and "Channel search." There are two main differences between these screens, which we will control through a prop — &lt;code&gt;channelsOnly&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"Jump to channel screen" doesn't have a header&lt;/li&gt;
&lt;li&gt;"Channel search screen" doesn't have a horizontal list of recent direct messaging conversation members.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Also, we need to display a list of recent conversations when the user opens this modal. We can use the cached list of recent conversations in &lt;code&gt;CacheService&lt;/code&gt; (which we populated in the &lt;code&gt;ChannelList&lt;/code&gt; component via the &lt;code&gt;useWatchedChannels&lt;/code&gt; hook) to avoid extra calls to the &lt;code&gt;queryChannels&lt;/code&gt; API endpoint.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Assign the &lt;code&gt;ChannelSearchScreen&lt;/code&gt; component to its respective &lt;code&gt;ModalStack.Screen&lt;/code&gt; in &lt;code&gt;App.js&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  New Message Screen
&lt;/h2&gt;

&lt;p&gt;Highlights of this screen (&lt;code&gt;NewMessageScreen&lt;/code&gt;) are as following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inputbox on top is a multi-select input. One can select multiple users there. This can be quickly built as a separate component — &lt;code&gt;UserSearch&lt;/code&gt;. Expose &lt;code&gt;onChangeTags&lt;/code&gt; callback as a prop function to give parent component access to selected users.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserSearch&lt;/code&gt; component uses &lt;code&gt;queryUsers&lt;/code&gt; endpoint provided available on chat client. Please check &lt;a href="https://getstream.io/chat/docs/query_users/?language=js&amp;amp;q=queryUser" rel="noopener noreferrer"&gt;docs for &lt;code&gt;queryUser&lt;/code&gt; endpoint&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;When the user focuses on the input box at the bottom of the screen, the app should create a conversation between the already selected users in the top (&lt;code&gt;UserSearch&lt;/code&gt;) input box. We handle this in the &lt;code&gt;onFocus&lt;/code&gt; handler for the input box at the bottom of the screen.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now assign the &lt;code&gt;NewMessageScreen&lt;/code&gt; component to its respective &lt;code&gt;ModalStack.Screen&lt;/code&gt; in &lt;code&gt;App.js&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Message Search Screen
&lt;/h3&gt;

&lt;p&gt;We are going to implement a global search for message text on this screen — &lt;code&gt;MessageSearchScreen&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The official Slack app provides richer features such as search in a specific channel or search by attachments. Here, we are keeping it limited to a global search, although channel-specific search is also possible using &lt;a href="https://getstream.io/chat/docs/search/?language=js" rel="noopener noreferrer"&gt;Stream Search API&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Global message search is relatively heavy for the backend so that search won't happen onChangeText, but when the user presses the search button explicitly. TextInput component has &lt;a href="https://reactnative.dev/docs/textinput#returnkeytype" rel="noopener noreferrer"&gt;&lt;code&gt;returnKeyType&lt;/code&gt;&lt;/a&gt; prop which we need for our use case.&lt;/li&gt;
&lt;li&gt;Component uses &lt;code&gt;search&lt;/code&gt; endpoint available on chat clients. Please check &lt;a href="https://getstream.io/chat/docs/search/?language=js" rel="noopener noreferrer"&gt;docs for message endpoint&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Search results display a list of messages; when pressed, they should go to the channel screen on that particular message. We are going to build a separate screen for this — &lt;code&gt;TargettedMessageChannelScreen&lt;/code&gt;. This component is quite similar to &lt;code&gt;ChannelScreen&lt;/code&gt;, but it queries the channel at a specific message (provided through props) instead of the latest message as follows:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;When the user lands on this screen, he can see the list of past searches. Store every search text in AsyncStorage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copy the following components in your app:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Assign the &lt;code&gt;MessageSearchScreen&lt;/code&gt; and &lt;code&gt;TargettedMessageChannelScreen&lt;/code&gt; component to its respective &lt;code&gt;ModalStack.Screen&lt;/code&gt; in &lt;code&gt;App.js&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Implementation for additional more screens (shown in screenshots below) is available in &lt;a href="https://github.com/GetStream/slack-clone-react-native/" rel="noopener noreferrer"&gt;slack-clone-react-native&lt;/a&gt; repository. If you managed to follow the tutorial so far, implementation of following screens should be easy to understand.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-react-native/tree/master/src/screens/DirectMessagesScreen.js" rel="noopener noreferrer"&gt;Direct Messages screen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-react-native/tree/master/src/screens/MentionsSearch.js" rel="noopener noreferrer"&gt;Mentions screen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-react-native/tree/master/src/screens/DraftsScreen.js" rel="noopener noreferrer"&gt;Draft Messages screen&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Congratulations! 👏
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fb5c1176ca5f8c9d43dae34d3bc5d6c5d%2Fcombine-images.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fb5c1176ca5f8c9d43dae34d3bc5d6c5d%2Fcombine-images.png" alt="Chat Slack Clone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You've completed Part 3, the final step, of our tutorial on building a Slack clone using the &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream’s Chat&lt;/a&gt; API with &lt;a href="https://www.npmjs.com/package/stream-chat-react-native" rel="noopener noreferrer"&gt;React Native&lt;/a&gt;. I hope you found this tutorial helpful!&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>slackclone</category>
      <category>chat</category>
      <category>getstream</category>
    </item>
    <item>
      <title>Tutorial: How to Build a Slack Clone with React Native — Part 2</title>
      <dc:creator>Vishal Narkhede</dc:creator>
      <pubDate>Sat, 31 Oct 2020 15:01:48 +0000</pubDate>
      <link>https://forem.com/vishalnarkhede/how-to-build-slack-clone-with-react-native-part-2-g5</link>
      <guid>https://forem.com/vishalnarkhede/how-to-build-slack-clone-with-react-native-part-2-g5</guid>
      <description>&lt;p&gt;React Native has come a long way since its first release in 2015. In fact, it has enough components, APIs, and supporting libraries in its present state that you can re-create every app that's out there on the Google Play Store or Apple App Store in no time!&lt;/p&gt;

&lt;p&gt;In this series, we will demonstrate how you can build a clone of Slack using React Native. Slack is a widely used messaging&lt;br&gt;
platform for workplaces, and it's quite feature-rich. React Native can handle the front-end side of things for us while relying on &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream Chat&lt;/a&gt;, which is equally seamless, for the back-end.&lt;/p&gt;

&lt;p&gt;In April 2020, Stream published a &lt;a href="https://getstream.io/blog/slack-clone-with-stream-chat-part-1/" rel="noopener noreferrer"&gt;Part 1&lt;/a&gt; of this series. There, we covered how to build Slack-type screens for navigation, message lists, and channel lists. Slack designs have changed quite a lot since then, so we will build a Slack clone from scratch with updated designs and additional features.&lt;/p&gt;

&lt;p&gt;We have decided to divide this tutorial into two parts (Part 2 and &lt;a href="https://getstream.io/blog/slack-clone-with-stream-chat-part-3/" rel="noopener noreferrer"&gt;Part 3&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;In Part 2 (this tutorial) and 3 of this series, we will focus on the following items:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dev Environment Setup&lt;/li&gt;
&lt;li&gt;Project Setup&lt;/li&gt;
&lt;li&gt;Navigation&lt;/li&gt;
&lt;li&gt;Channel List&lt;/li&gt;
&lt;li&gt;Message List&lt;/li&gt;
&lt;li&gt;Action Sheet&lt;/li&gt;
&lt;li&gt;Reaction Picker&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: The objective of this tutorial is not intended to help you build a production-ready clone of the Slack application (because it already exists). Rather, this tutorial is a comprehensive guide on how to build real-time chat using UI components provided by Stream's Chat and Messaging API and SDKs.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Resources 👇
&lt;/h2&gt;

&lt;p&gt;Below are a few links to help you if you get stuck along the way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-react-native" rel="noopener noreferrer"&gt;Official Slack Clone Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-expo" rel="noopener noreferrer"&gt;Official Slack Clone Repo for Expo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactnavigation.org/" rel="noopener noreferrer"&gt;Documentation for React Navigation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/stream-chat-react-native" rel="noopener noreferrer"&gt;Stream Chat Component Library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Quick Test 🥽
&lt;/h2&gt;

&lt;p&gt;If you would like to see the final state of the app in action quickly, clone the following expo example of the slack clone and run it on the emulator or a phone:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Step 1: Setup 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dev Environment Setup
&lt;/h3&gt;

&lt;p&gt;Before getting started, make sure you have a development environment setup for react-native. Read the &lt;strong&gt;Installing Dependencies&lt;/strong&gt; section of the &lt;a href="https://reactnative.dev/docs/environment-setup" rel="noopener noreferrer"&gt;official react-native docs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;p&gt;Once you have a dev environment setup, create a new react-native application:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We will be using the svg format for all the icons that you see across the app. And thus, we are using &lt;code&gt;react-native-svg-transformer&lt;/code&gt; dependency. Follow the installation steps required for this dependency: &lt;a href="https://github.com/kristerkari/react-native-svg-transformer#installation-and-configuration" rel="noopener noreferrer"&gt;https://github.com/kristerkari/react-native-svg-transformer#installation-and-configuration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slack uses Lato font, which is available free on &lt;a href="https://fonts.google.com/" rel="noopener noreferrer"&gt;https://fonts.google.com/&lt;/a&gt;. For visual parity, we need to import the font into our app. To do so, create a file named &lt;code&gt;react-native.config.js&lt;/code&gt; in the project directory and paste the following contents:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You can download Lato font files from the &lt;code&gt;slack-clone&lt;/code&gt; project [repository](&lt;a href="https://github.com/GetStream/slack-clone-react-native/masterand" rel="noopener noreferrer"&gt;https://github.com/GetStream/slack-clone-react-native/masterand&lt;/a&gt; icons from [here](&lt;a href="https://github.com/GetStream/slack-clone-react-native/tree/master" rel="noopener noreferrer"&gt;https://github.com/GetStream/slack-clone-react-native/tree/master&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can download the fonts from the Google Fonts website &lt;a href="https://fonts.google.com/specimen/Lato" rel="noopener noreferrer"&gt;here&lt;/a&gt;. You will see a &lt;code&gt;Download family&lt;/code&gt; button at the top.&lt;/p&gt;

&lt;p&gt;Next, prepare the following directory structure in the root directory of the project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F0061d760c88fbf2489e272f587569651%2Fimage10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F0061d760c88fbf2489e272f587569651%2Fimage10.png" alt="Stream Chat Clone - Directory List"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the following command:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Also, change the content of index.js in the root directory to the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This completes the setup required for your slack-clone app. You should now be able to run the app with the following command to launch the app on an emulator. Once started, you will see a welcome screen to React Native.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F580197719c463804f56f85612f2eba62%2Fimage16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F580197719c463804f56f85612f2eba62%2Fimage16.png" alt="React Native - Welcome Screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Components 🧬
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Utilities
&lt;/h3&gt;

&lt;p&gt;Here's how to add a few essential utilities into your app.&lt;/p&gt;

&lt;p&gt;Create the following directories for storing svg icons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/images/svgs/channel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/images/svgs/channel-list&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/images/svgs/message&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/images/svgs/profile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/images/svgs/tab-bar&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, download all the svg icons from &lt;a href="https://github.com/GetStream/slack-clone-react-native/tree/master/src/images/svgs" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To make it easy to use svg icons across the app, create a separate component, &lt;code&gt;SVGIcon&lt;/code&gt;, which accepts type, height, and width props and renders the icon on view. Create a component in &lt;code&gt;src/components/SVGIcon.js&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We will add support for dark mode, so we need to create separate themes for the app. We are using a theme provider from react-navigation for this project. You can check out the documentation to know more about &lt;a href="https://reactnavigation.org/docs/themes/" rel="noopener noreferrer"&gt;themes&lt;/a&gt; and &lt;a href="https://reactnavigation.org/docs/use-theme" rel="noopener noreferrer"&gt;useTheme hook&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Next, create a Text component with the Lato font-family, which will used across the app.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Copy the rest of the utils from &lt;a href="https://github.com/GetStream/slack-clone-react-native/tree/master/src/utils" rel="noopener noreferrer"&gt;here&lt;/a&gt; to &lt;code&gt;src/utils/&lt;/code&gt; directory. You can read through the code comments about it, but they will make more sense as we use them through this tutorial.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;utils/useStreamChatTheme.js&lt;/code&gt; file exports a hook, which provides a theme for Stream Chat components. If you are not aware of theming for chat components from &lt;a href="https://www.npmjs.com/package/stream-chat-react-native" rel="noopener noreferrer"&gt;stream-chat-react-native&lt;/a&gt; library, please check &lt;a href="https://getstream.io/chat/react-native-chat/tutorial/#custom-styles" rel="noopener noreferrer"&gt;this link&lt;/a&gt;. We need these styles to change according to the system theme (dark-light), so we have built a hook around this theme object in &lt;code&gt;src/utils/useStreamChatTheme.js&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Navigation
&lt;/h3&gt;

&lt;p&gt;Before we dive into the navigation part, lets first design the screen header and floating action button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F08b7ff184e6d2e34c972a2a2e885540f%2Fheader-fab.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F08b7ff184e6d2e34c972a2a2e885540f%2Fheader-fab.png" alt="Basic Bottom Navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ScreenHeader&lt;/code&gt; component is below. We are using the &lt;code&gt;useSafeAreaInsets&lt;/code&gt; hook to avoid overlapping content with the top inset of a device such as the iPhone 11.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The floating action button, which opens the new message screen (which we will implement later), is as follows:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let's move on to setting up the navigation for our app, similar to Slack. Replace App.js with the following. It's essential to place navigation components at the correct position in the &lt;a href="https://reactnavigation.org/docs/stack-navigator/" rel="noopener noreferrer"&gt;stack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We need screens such as a draft screen or thread screen outside of the bottom tab navigation, so they go at the root level. Screens such as channel searches are a perfect example of &lt;a href="https://reactnavigation.org/docs/modal/" rel="noopener noreferrer"&gt;react-navigation modals&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If you refresh the app, you should see the following navigation. You can toggle the dark mode by pressing &lt;code&gt;cmd + shift + a&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fdae15067ba07778471c89e7b778436c0%2Fbasic-nav-2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fdae15067ba07778471c89e7b778436c0%2Fbasic-nav-2.gif" alt="Basic Navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Channel List Screen
&lt;/h3&gt;

&lt;p&gt;Now, set up the channel list screen. This is similar to how we did it in &lt;a href="https://getstream.io/blog/slack-clone-with-stream-chat-part-1/" rel="noopener noreferrer"&gt;Part 1&lt;/a&gt; of the tutorial, with few changes.&lt;/p&gt;

&lt;p&gt;Let's outline the important specs that we need to implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Channels to be grouped by&lt;/li&gt;
&lt;li&gt;Unread channels and unread conversations ( &lt;code&gt;directMessagingConversations&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Channels&lt;/li&gt;
&lt;li&gt;Direct Message (&lt;code&gt;directMessagingConversations&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Channels in our case are defined by a conversation with a non-empty name. &lt;code&gt;directMessagingConversations&lt;/code&gt; are defined by conversations without a name.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unread channel labels are bold&lt;/li&gt;
&lt;li&gt;In case of one-to-one conversation (a subgroup of &lt;code&gt;directMessagingConversations&lt;/code&gt;), users have a presence indicator next to their name — green if they are online, otherwise hollow circles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the following files to the project:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;useWatchedChannels&lt;/code&gt; hook makes two calls to the &lt;code&gt;queryChannels&lt;/code&gt; API to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch all group channels (conversations with a name)&lt;/li&gt;
&lt;li&gt;Fetch all direct messages (conversations without a name)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once fetched, results are sorted into three variables:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;unreadChannels&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;readChannels&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;directMessagingConversations&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can reuse the queried channel data in other screens; thus, we are caching it in &lt;code&gt;CacheService&lt;/code&gt;. To keep things simple, use an object for caching. You can use redux or some other state management service for this purpose.&lt;/p&gt;

&lt;p&gt;Reload the app, and you should see the &lt;code&gt;ChannelList&lt;/code&gt; screen working in the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Channel Screen
&lt;/h3&gt;

&lt;p&gt;Let's start by building the header for the channel screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fe5bdec35805604a42dbe80e430400af9%2FScreenshot-2020-10-31-at-22-10-38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fe5bdec35805604a42dbe80e430400af9%2FScreenshot-2020-10-31-at-22-10-38.png" alt="Channel Header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new component for channel header:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now we can build a &lt;code&gt;ChannelScreen&lt;/code&gt; component with the following functionality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Renders a MessageList component, with customized UI component to be displayed for message bubble - &lt;code&gt;MessageSlack&lt;/code&gt; (&lt;a href="https://github.com/GetStream/stream-chat-react-native/wiki/Cookbook-(2.x.x)#how-to-customize-message-component" rel="noopener noreferrer"&gt;🔗&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Renders a MessageInput component, with customized UI component to be shown for input box - &lt;code&gt;InputBox&lt;/code&gt; (&lt;a href="https://github.com/GetStream/stream-chat-react-native/wiki/Cookbook-(2.x.x)#how-to-change-layout-of-messageinput-message-text-input-box-component" rel="noopener noreferrer"&gt;🔗&lt;/a&gt;). Copy the updated copy of component &lt;a href="https://github.com/GetStream/slack-clone-react-native/blob/master/src/components/InputBox.js" rel="noopener noreferrer"&gt;InputBox&lt;/a&gt; to src/components directory.&lt;/li&gt;
&lt;li&gt;When the user navigates away from &lt;code&gt;ChannelScreen&lt;/code&gt;, we store the user object in &lt;a href="https://react-native-async-storage.github.io/async-storage/docs/install/" rel="noopener noreferrer"&gt;AsyncStorage&lt;/a&gt; as well as the message last type into the input box. This is required for the &lt;code&gt;DraftMessages&lt;/code&gt; screen. In our code sample, we created the &lt;a href="https://github.com/GetStream/slack-clone-react-native/blob/master/src/utils/AsyncStore.js" rel="noopener noreferrer"&gt;AsyncStore&lt;/a&gt; utility, which is an interface between &lt;code&gt;AsyncStorage&lt;/code&gt; and app-level code, to help avoid boilerplate code around stringifying and parsing of values.&lt;/li&gt;
&lt;li&gt;When a user lands on the &lt;code&gt;ChannelScreen&lt;/code&gt;, check if a draft message exists in &lt;code&gt;AsyncStorage&lt;/code&gt; for the current channel. If yes, set that message as the initial value of the input box.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;MessageSlack&lt;/code&gt; component is as follows:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If you have read Part 1 of this tutorial, then you will recognize most of the props on MessageSimple component. Copy updated code for these components to &lt;code&gt;src/components&lt;/code&gt; directory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-react-native/blob/master/src/components/MessageAvatar.js" rel="noopener noreferrer"&gt;MessageAvatar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-react-native/blob/master/src/components/MessageHeader.js" rel="noopener noreferrer"&gt;MessageHeader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-react-native/blob/master/src/components/MessageText.js" rel="noopener noreferrer"&gt;MessageText&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-react-native/blob/master/src/components/UrlPreview.js" rel="noopener noreferrer"&gt;UrlPreview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-react-native/blob/master/src/components/Giphy.js" rel="noopener noreferrer"&gt;Giphy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;MessageFooter&lt;/code&gt;, &lt;code&gt;ReactionPicker&lt;/code&gt;, and &lt;code&gt;MessageActionSheet&lt;/code&gt; are the new elements introduced in this version of the Slack clone.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;MessageFooter&lt;/code&gt; component now provides a Slack type reaction selector (shown in the following screenshot). &lt;code&gt;ReactionPicker&lt;/code&gt; is just another component, whose visibility is controlled by two handles — &lt;code&gt;openReactionPicker&lt;/code&gt; and &lt;code&gt;dismissReactionPicker&lt;/code&gt;. These two functions are available on MessageSimple and all its children as props.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F986c62fe9575b3344df2c272145d249d%2Freaction-picker.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F986c62fe9575b3344df2c272145d249d%2Freaction-picker.gif" alt="Slack Type Reaction Picker"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Notice the &lt;a href="https://developer.aliyun.com/mirror/npm/package/react-native-haptic" rel="noopener noreferrer"&gt;react-native-haptics&lt;/a&gt; dependency add additional haptic feedback on touch on an iOS device.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ActionSheet&lt;/code&gt; prop was introduced in &lt;a href="https://www.npmjs.com/package/stream-chat-react-native" rel="noopener noreferrer"&gt;stream-chat-react-native@2.0.0&lt;/a&gt; on the &lt;code&gt;MessageSimple&lt;/code&gt; component. In our case, we need to build a Slack type action sheet, which is quite different than what &lt;code&gt;stream-chat-react-native&lt;/code&gt; provides out-of-the-box:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F94176a864a13a93445067f1dfc9347ee%2FScreenshot-2020-11-01-at-10-07-18.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F94176a864a13a93445067f1dfc9347ee%2FScreenshot-2020-11-01-at-10-07-18.png" alt="React Native Action Sheet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code for &lt;code&gt;MessageActionSheet&lt;/code&gt; looks like the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now assign the ChannelScreen component to its respective &lt;code&gt;HomeStack.Screen&lt;/code&gt; in &lt;code&gt;App.js&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If you reload the app, you should see the &lt;code&gt;ChannelScreen&lt;/code&gt; working correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Congratulations! 👏
&lt;/h2&gt;

&lt;p&gt;You've completed Part 2 of our tutorial on building a Slack clone using the &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream’s Chat&lt;/a&gt; API with &lt;a href="https://www.npmjs.com/package/stream-chat-react-native" rel="noopener noreferrer"&gt;React Native&lt;/a&gt;. In &lt;a href="https://getstream.io/blog/slack-clone-with-stream-chat-part-3/" rel="noopener noreferrer"&gt;Part 3&lt;/a&gt; of the tutorial, we cover various search screens on the Slack clone app and threads screen.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>slackclone</category>
      <category>chat</category>
      <category>getstream</category>
    </item>
    <item>
      <title>Tutorial: How to Build a Slack Clone with React Native — Part 1</title>
      <dc:creator>Vishal Narkhede</dc:creator>
      <pubDate>Fri, 24 Apr 2020 10:43:57 +0000</pubDate>
      <link>https://forem.com/vishalnarkhede/tutorial-how-to-build-a-slack-clone-with-react-native-part-1-37kn</link>
      <guid>https://forem.com/vishalnarkhede/tutorial-how-to-build-a-slack-clone-with-react-native-part-1-37kn</guid>
      <description>&lt;p&gt;&lt;a href="https://reactnative.dev/" rel="noopener noreferrer"&gt;React Native&lt;/a&gt; has a significant footprint in the mobile development world. And with every new release, it gets better and better in terms of development speed and performance. Building a chat application used to be a massive chunk of work, but with the power of react-native and &lt;a href="https://getstream.io/chat/" rel="noopener noreferrer"&gt;Stream Chat&lt;/a&gt;, it's possible to create a messaging app within minutes.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will build a clone of Slack, a messaging platform for workplaces. The Slack application comes with plenty of features. In this part of our tutorial, we will cover Slack’s following UI/UX features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Channel list navigation&lt;/li&gt;
&lt;li&gt;Input box&lt;/li&gt;
&lt;li&gt;Message row&lt;/li&gt;
&lt;li&gt;Reaction list&lt;/li&gt;
&lt;li&gt;Giphy cards&lt;/li&gt;
&lt;li&gt;Enriched URL previews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result will look like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F846c9491c65e1d941902f5276c597b7f%2Ffinal.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1237%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F846c9491c65e1d941902f5276c597b7f%2Ffinal.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1237%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" alt="Stream Chat - Final Slack Clone - Preview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The objective of this tutorial is not intended to help you build a production-ready clone of the Slack application (because it already exists). Instead, this tutorial will serve as a go-to guide to help you understand how you can build real-life chat using UI components provided by Stream's Chat and Messaging API and SDKs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you feel lost during the tutorial, the  following resources will be helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://getstream.io/chat/react-native-chat/tutorial/" rel="noopener noreferrer"&gt;React Native Chat Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://getstream.github.io/stream-chat-react-native/" rel="noopener noreferrer"&gt;Stream’s React Native Chat Components&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; If you want to send a message to the app, to check if the real-time feature is working or not, use this &lt;a href="https://codepen.io/vishtree/pen/YzyyEBG?editors=0010" rel="noopener noreferrer"&gt;CodePen&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Resources 👇
&lt;/h2&gt;

&lt;p&gt;Here are a few links to help you if you get stuck along the way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-react-native/tree/slack-clone-1.0" rel="noopener noreferrer"&gt;Official Slack Clone Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/slack-clone-expo/tree/slack-clone-1.0" rel="noopener noreferrer"&gt;Official Slack Clone Repo for Expo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactnavigation.org/" rel="noopener noreferrer"&gt;Documentation for React Navigation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GetStream/stream-chat-react-native" rel="noopener noreferrer"&gt;Stream Chat Component Library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Test 🥽
&lt;/h2&gt;

&lt;p&gt;If you would like to see the final state of the app in action quickly, please clone the following expo example of the slack clone and run it on the emulator or a phone:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Step 1: Setup 🛠️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dev Environment Setup
&lt;/h3&gt;

&lt;p&gt;Before getting started, please make sure you have a development environment setup for react-native. Please read the &lt;strong&gt;Installing Dependencies&lt;/strong&gt; section of the &lt;a href="https://reactnative.dev/docs/environment-setup" rel="noopener noreferrer"&gt;official react-native docs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;p&gt;Once you have a dev environment setup, create a new react-native application:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Slack uses a Lato font, which is freely available on &lt;a href="https://fonts.google.com/" rel="noopener noreferrer"&gt;https://fonts.google.com/&lt;/a&gt;. For visual parity, we need to import the font into our app. To do so, create a file named &lt;code&gt;react-native.config.js&lt;/code&gt; in the project directory  and paste the following contents:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You can download Lato font files from the &lt;code&gt;slack-clone&lt;/code&gt; project &lt;a href="https://github.com/GetStream/slack-clone-react-native/blob/slack-clone-1.0/src/fonts" rel="noopener noreferrer"&gt;repository&lt;/a&gt; and icons from &lt;a href="https://github.com/GetStream/slack-clone-react-native/blob/slack-clone-1.0/src/images" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Alternatively, you can download the fonts from the &lt;a href="https://fonts.google.com/specimen/Lato" rel="noopener noreferrer"&gt;Google Fonts website&lt;/a&gt;. You will see a button titled &lt;code&gt;Download family&lt;/code&gt; at the top.&lt;/p&gt;

&lt;p&gt;Next, prepare the following directory structure in the root directory of the project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F0061d760c88fbf2489e272f587569651%2Fimage10.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D2048%26ixlib%3Dphp-1.2.1%26w%3D1536%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F0061d760c88fbf2489e272f587569651%2Fimage10.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D2048%26ixlib%3Dphp-1.2.1%26w%3D1536%26wpsize%3D2048x2048" alt="Stream Chat Clone - Directory List"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please run the following command at this step:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;With these steps in place, this completes the setup required for your slack-clone app. You should now be able to run the app with the following command to launch the app on an emulator. Once started, you will see a welcome screen to React Native.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F580197719c463804f56f85612f2eba62%2Fimage16.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D2048%26ixlib%3Dphp-1.2.1%26w%3D1130%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F580197719c463804f56f85612f2eba62%2Fimage16.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D2048%26ixlib%3Dphp-1.2.1%26w%3D1130%26wpsize%3D2048x2048" alt="React Native - Welcome Screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Components 🏗️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Basic Navigation Drawer
&lt;/h3&gt;

&lt;p&gt;Let's first create a basic drawer navigation in our app. Replace the content of &lt;code&gt;App.js&lt;/code&gt; with the following code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After you’ve completed this, you should see the essential Slack-like drawer navigation if you check your emulator.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F479d3ef4c8e071940d19d9ed06c5af76%2Fbase.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1807%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F479d3ef4c8e071940d19d9ed06c5af76%2Fbase.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1807%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" alt="Stream Slack Clone - Getting Started"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Channel List Navigation 🧭
&lt;/h2&gt;

&lt;p&gt;Now let's create a channel list navigation and add it to the drawer that we just created. For the Slack navigation drawer, some essential UI elements that we will focus on are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Channels are grouped by

&lt;ul&gt;
&lt;li&gt;Unread channels&lt;/li&gt;
&lt;li&gt;Channels (read channels)&lt;/li&gt;
&lt;li&gt;Direct messages - this is perfect use case of &lt;a href="https://reactnative.dev/docs/sectionlist" rel="noopener noreferrer"&gt;SectionList&lt;/a&gt; in react-native&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Unread channel labels are bold&lt;/li&gt;

&lt;li&gt;Direct message users have a presence indicator next to their name - green if they are online, otherwise hollow circles.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Let's create a file named &lt;code&gt;src/components/ChannelList.js&lt;/code&gt;. You can copy the contents of the following code snippet into your newly created file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Additionally,  replace the &lt;code&gt;ChannelListDrawer&lt;/code&gt; component in &lt;code&gt;App.js&lt;/code&gt; with the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If you are familiar with react-native, this piece of code should be pretty straightforward. We have added a &lt;code&gt;SectionList&lt;/code&gt; component with three sections: unread, channels, direct messages. You should see the following in your app so far:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fd4e3b42a49132c9495dea567768cf5fd%2Fimage5.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D2048%26ixlib%3Dphp-1.2.1%26w%3D1162%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2Fd4e3b42a49132c9495dea567768cf5fd%2Fimage5.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D2048%26ixlib%3Dphp-1.2.1%26w%3D1162%26wpsize%3D2048x2048" alt="Stream Chat Clone - Base"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's populate the &lt;code&gt;SectionList&lt;/code&gt; with some channels. As I mentioned earlier in the tutorial, we are going to use Stream’s chat infrastructure. &lt;/p&gt;

&lt;p&gt;Let's start by creating a Stream Chat client in &lt;code&gt;App.js&lt;/code&gt; and passing it as a prop to the &lt;code&gt;ChannelList&lt;/code&gt; component.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We have also added a prop function named &lt;code&gt;changeChannel&lt;/code&gt;, which takes care of opening the channel screen and passing the provided channel ID to it. We will use this function as an &lt;code&gt;onPress&lt;/code&gt; handler for the &lt;code&gt;ChannelListItem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let’s create a hook in &lt;code&gt;ChannelList.js&lt;/code&gt; file, which takes care of querying channels. Later, we will update them in real-time when new messages arrive, or we move messages between groups.&lt;/p&gt;

&lt;p&gt;If you are not familiar with React hooks, here are some great resources to get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/docs/hooks-intro.html" rel="noopener noreferrer"&gt;Introduction to React Hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://usehooks.com" rel="noopener noreferrer"&gt;Easy to Understand React Hook Recipes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This hook queries the channels using the Stream client.  It sorts them into three categories, which are returned as state variables: &lt;code&gt;unreadChannels&lt;/code&gt;, &lt;code&gt;readChannels&lt;/code&gt;, &lt;code&gt;oneOnOneConversations&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;renderChannelListItem&lt;/code&gt; function currently returns &lt;code&gt;&amp;lt;Text&amp;gt;{channel.id}&amp;lt;/Text&amp;gt;&lt;/code&gt;, which displays the ID of the channel. Let's create a proper UI for this item that resembles Slack.&lt;/p&gt;

&lt;p&gt;Create a new component in a separate file named &lt;code&gt;src/components/ChannelListItem.js&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This component will ensure different styles based on whether it's a group channel or one-on-one conversation, or if it's an unread channel. It will also check whether or not it contains user mentions.&lt;/p&gt;

&lt;p&gt;Now let's use our &lt;code&gt;ChannelListItem&lt;/code&gt; component in the &lt;code&gt;ChannelList&lt;/code&gt; component’s &lt;code&gt;SectionList&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can note here, I have supplied &lt;code&gt;isUnread: true&lt;/code&gt; to unread section data. This way, I can tell the &lt;code&gt;renderChannelRow&lt;/code&gt; function if the current channel to render is unread or not. &lt;/p&gt;

&lt;p&gt;It's not necessary since you can quickly get an unread count of the channel in &lt;code&gt;renderChannelRow&lt;/code&gt; using &lt;code&gt;channel.unreadCount()&lt;/code&gt; to decide if it's read or unread. But it's just a way to avoid extra calls to &lt;code&gt;channel.countUnread()&lt;/code&gt;, which essentially loops through messages.&lt;/p&gt;

&lt;p&gt;If you reload your app, you should see a few channels populated in the channels list, as shown in the screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F8cb0c6563d675134b95c3bf474fc70f3%2Fimage3.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D2048%26ixlib%3Dphp-1.2.1%26w%3D1130%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F8cb0c6563d675134b95c3bf474fc70f3%2Fimage3.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D2048%26ixlib%3Dphp-1.2.1%26w%3D1130%26wpsize%3D2048x2048" alt="Stream Chat Slack Clone - Notification Indicator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So far, &lt;code&gt;ChannelList&lt;/code&gt; works fine, but you will notice that it's not real-time. If a message is sent on some channel by another user, it won’t reflect on your &lt;code&gt;ChannelList&lt;/code&gt;. We need to implement event handlers in our &lt;code&gt;useWatchedChannels&lt;/code&gt; hook for this purpose.&lt;/p&gt;

&lt;p&gt;You can find detailed docs about Stream events &lt;a href="https://getstream.io/chat/docs/event_listening/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We are going to handle two events for tutorial purpose, but you can experiment with as many events as you want:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;message.new&lt;/code&gt; - this event tells us that there is a new message on some channel (channel data is included in the event object). In this case, we want to move the channel from either &lt;code&gt;readChannels&lt;/code&gt; or &lt;code&gt;oneOnOneConversations&lt;/code&gt; to &lt;code&gt;unreadChannels&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;message.read&lt;/code&gt; - this event tells us that some channel (data available in event object) was marked as read. In this case, we want to move the channel from &lt;code&gt;unreadChannels&lt;/code&gt;  to either &lt;code&gt;readChannels&lt;/code&gt; or &lt;code&gt;oneOnOneConversations&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Replace the &lt;code&gt;useWatchedChannels&lt;/code&gt; hook code with the following updated code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We have added another &lt;code&gt;useEffect&lt;/code&gt; hook here, which adds an event listener to our stream client and takes care of removing the listener when the component unmounts. The &lt;code&gt;handleEvent&lt;/code&gt; is an event handler that will take some action based on which event is received.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As an exercise, you can try adding handlers for other events such as &lt;code&gt;user.presence.changed&lt;/code&gt;, &lt;code&gt;channel.updated&lt;/code&gt; or &lt;code&gt;channel.deleted&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now try sending a message to some channel from this &lt;a href="https://codepen.io/vishtree/pen/YzyyEBG?editors=0010" rel="noopener noreferrer"&gt;CodePen&lt;/a&gt;, (which uses the user &lt;code&gt;Tommaso&lt;/code&gt;) and you should see the channel with a new message moving to the unread section.&lt;/p&gt;

&lt;p&gt;Now the last thing we need to take care of is the &lt;code&gt;onclick&lt;/code&gt; handler for &lt;code&gt;ChannelListItem&lt;/code&gt;. When an item is selected, we need to update the channel in the &lt;code&gt;ChannelScreen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This concludes our &lt;code&gt;ChannelList&lt;/code&gt; component. If you send a message to a channel in this list, you will see the event handler doing its job of updating the list UI accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Channel Screen 📱
&lt;/h2&gt;

&lt;p&gt;Let’s start by building the following channel header shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F8c2cf5ddc8dade54a518b9a0f4b7a2d9%2Fimage7.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D519%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F8c2cf5ddc8dade54a518b9a0f4b7a2d9%2Fimage7.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D519%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" alt="Stream Chat Slack Clone - Channel Name"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new file for header - &lt;code&gt;src/components/ChannelHeader.js&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;With this, we have added a hamburger icon on the left side of the screen, which, when clicked, will open the navigation drawer.&lt;/p&gt;

&lt;p&gt;We are still yet to put this &lt;code&gt;ChannelHeader&lt;/code&gt; in our &lt;code&gt;ChannelScreen&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;Update the &lt;code&gt;ChannelScreen&lt;/code&gt; component in &lt;code&gt;App.js&lt;/code&gt; with the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If you reload your app, you should see an empty channel screen with the header on top:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F59cde8525ce37464f9e70e3b7f14d894%2Fimage8.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D2048%26ixlib%3Dphp-1.2.1%26w%3D1130%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F59cde8525ce37464f9e70e3b7f14d894%2Fimage8.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D2048%26ixlib%3Dphp-1.2.1%26w%3D1130%26wpsize%3D2048x2048" alt="Stream Chat Clone - Empty Channel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's move onto adding &lt;code&gt;MessageList&lt;/code&gt; and &lt;code&gt;MessageInput&lt;/code&gt; components to our &lt;code&gt;ChannelScreen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These two components are provided by Stream as part of the &lt;a href="https://getstream.io/chat/react-native-chat/tutorial/#stream-app" rel="noopener noreferrer"&gt;react-native-sdk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please update the &lt;code&gt;ChannelScreen&lt;/code&gt; component with the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After this change, you will see messages and an input box at the bottom of our Channel Screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F73237d41893235543160d739bd8e81eb%2Freactions.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1865%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F73237d41893235543160d739bd8e81eb%2Freactions.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1865%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" alt="Stream Chat Slack Clone - Reactions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But it doesn’t quite look like Slack messages. So now we need to make changes to make it look like Slack. Here is the list of things in Slack UI that separates it from our current UI in the app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F9fc79ad7d5559e440959d6cb9346ef79%2Fimage4.jpg%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1940%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F9fc79ad7d5559e440959d6cb9346ef79%2Fimage4.jpg%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1940%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" alt="Stream Chat Slack Clone - Message"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user name is shown at the top of the message&lt;/li&gt;
&lt;li&gt;Avatars (circular user profile pics next to message) should be square&lt;/li&gt;
&lt;li&gt;Reactions should be at the bottom of the message&lt;/li&gt;
&lt;li&gt;Reaction counts should be shown next to each reaction&lt;/li&gt;
&lt;li&gt;URL preview should have a thick left grey border and its content alignment offset&lt;/li&gt;
&lt;li&gt;All the messages should be displayed on the left side of the screen&lt;/li&gt;
&lt;li&gt;GIFs are shown differently in slack channels&lt;/li&gt;
&lt;li&gt;Date separator between messages should be shown above a grey line&lt;/li&gt;
&lt;li&gt;Send and attach buttons should be below the input box.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will tackle these things one by one. Stream’s react-native SDK uses &lt;a href="https://github.com/GetStream/stream-chat-react-native/blob/master/src/components/MessageSimple/index.js" rel="noopener noreferrer"&gt;MessageSimple&lt;/a&gt; as the default message component. But you can also use a custom UI component as a message – &lt;a href="https://github.com/GetStream/stream-chat-react-native/blob/master/docs/cookbook.md#how-to-customize-message-component" rel="noopener noreferrer"&gt;reference here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, let’s add some basic custom theme styles. Let's create a custom message component (named &lt;code&gt;MessageSlack&lt;/code&gt;) which internally uses MessageSimple with modifications. The &lt;code&gt;MessageSimple&lt;/code&gt; component offers plenty of customizations. We will create our custom components for the following props, which are supported by the &lt;code&gt;MessageSimple&lt;/code&gt; component. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Please check the &lt;a href="https://github.com/GetStream/stream-chat-react-native/blob/master/docs/cookbook.md#how-to-customize-message-component" rel="noopener noreferrer"&gt;cookbook&lt;/a&gt; for more examples)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;MessageAvatar&lt;/li&gt;
&lt;li&gt;MessageFooter (which contains reactions)&lt;/li&gt;
&lt;li&gt;MessageHeader (which contains the sender's username)&lt;/li&gt;
&lt;li&gt;MessageText&lt;/li&gt;
&lt;li&gt;UrlPreview (used to display enriched URL preview)&lt;/li&gt;
&lt;li&gt;Giphy (used to show Giphy cards)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's create each of these components:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/components/MessageSlack.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;src/components/MessageFooter.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;src/components/MessageHeader.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;src/components/MessageText.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;src/components/MessageAvatar.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;src/components/UrlPreview.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;src/components/Giphy.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We also need a custom &lt;code&gt;DateSeparator&lt;/code&gt; component. The default that is used by Stream shows the date in the middle of a spacer/line. However, in the Slack UI, it is shown on top in a grey spacer/line.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/components/DateSeparator.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, after this, all you need to do is pass &lt;code&gt;MessageSlack&lt;/code&gt; and &lt;code&gt;DateSeparator&lt;/code&gt; to the &lt;code&gt;MessageList&lt;/code&gt; component in &lt;code&gt;App.js.&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If you refresh the app, you will see the UI now has much better parity with the slack UI.&lt;/p&gt;

&lt;p&gt;We still need to add some final finishing touches, such as the square avatar. The avatar should be aligned with the top of the message, and messages should not have borders, so we'll need to make some small alignment tweaks as well.&lt;/p&gt;

&lt;p&gt;We will take care of them by theming the chat component. Please read the Custom Styles section of Stream’s react-native &lt;a href="https://getstream.io/chat/react-native-chat/tutorial#custom-styles" rel="noopener noreferrer"&gt;chat tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;src/stream-chat-theme.js&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now pass this theme to the &lt;code&gt;Chat&lt;/code&gt; component in the &lt;code&gt;ChannelScreen&lt;/code&gt; within App.js, as shown below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And that's it! You should see beautiful Slack-like messages on the screen. 😺&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F3a2354e96a0f5a042d7924078c06f213%2Ffinal-2.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1865%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F3a2354e96a0f5a042d7924078c06f213%2Ffinal-2.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1865%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" alt="Stream Chat Slack Clone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Input Box 👨‍💻
&lt;/h2&gt;

&lt;p&gt;Now let's move on to the input box at the bottom. The &lt;code&gt;MessageInput&lt;/code&gt; component (from Stream) accepts &lt;code&gt;Input&lt;/code&gt; as a custom UI component prop to be shown for the input box. Let's create this custom component in &lt;code&gt;src/components/InputBox.js&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The following components that we have used in the InputBox are provided by Stream’s react-native SDK, which takes care of plenty of things for us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AutoCompleteInput&lt;/code&gt; - takes care of all input box features such as mentions, sending messages, maintaining enabled/disabled state, etc.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SendButton&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AttachButton&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All we have done is shuffle around the internal components of the &lt;code&gt;MessageInput&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is important to note here that you must pass the entire prop object to &lt;code&gt;AutoCompleteInput&lt;/code&gt;, &lt;code&gt;SendButton&lt;/code&gt;, and &lt;code&gt;AttachButton&lt;/code&gt;. Hence, all the handlers present in &lt;code&gt;MessageInput&lt;/code&gt; are accessible to these components.&lt;/p&gt;

&lt;p&gt;Now pass this &lt;code&gt;InputBox&lt;/code&gt; component to &lt;code&gt;MessageInput&lt;/code&gt; in the &lt;code&gt;ChannelScreen&lt;/code&gt; component of &lt;code&gt;App.js&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The final version of the &lt;code&gt;ChannelScreen&lt;/code&gt; component is as follows:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;:  the extra prop to MessageInput component - &lt;code&gt;additionalTextInputProps&lt;/code&gt;. That is to modify the placeholder of the input box.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F846c9491c65e1d941902f5276c597b7f%2Ffinal.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1237%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstream-blog-v2.imgix.net%2Fblog%2Fwp-content%2Fuploads%2F846c9491c65e1d941902f5276c597b7f%2Ffinal.png%3Fauto%3Dcompress%252Cformat%26fit%3Dscale%26h%3D1237%26ixlib%3Dphp-1.2.1%26w%3D2048%26wpsize%3D2048x2048" alt="Stream Chat - Final Slack Clone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Congratulations! 👏
&lt;/h2&gt;

&lt;p&gt;This concludes part one of our tutorial on building a Slack clone using Stream’s React Native Chat Components. I hope you found this tutorial useful, and I look forward to hearing your feedback.&lt;/p&gt;

&lt;p&gt;In the next part of the tutorial – which will be published later – we will cover additional UI components and their functionality, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Threads&lt;/li&gt;
&lt;li&gt;Channel search&lt;/li&gt;
&lt;li&gt;Action sheets&lt;/li&gt;
&lt;li&gt;Unread message notifications&lt;/li&gt;
&lt;li&gt;And more!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>chat</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
