Activity Feeds: React Native Timeline

This tutorial is an introduction to how you can use the Stream Feed API and React Native to create a timeline news feed on mobile applications. In the end, you will have a fully functioning activity feed with built-in support for real-time updates, URL enrichment, likes, and image uploads.


At the end of the guide you can find links to resources and docs to learn about other functionality such as: comments, notification feeds and aggregation.

Make sure to check out our React Native Chat and React Chat tutorials! Build Feeds and Chat in less time with React and Stream!

Setup

To use the code from this tutorial, you need a working Node development environment with React Native and Expo. We suggest creating a fresh project using expo-cli.

Make sure that you have a recent version of Node (>=10) and Yarn installed.

yarn global add expo-cli

Run the following commands to create a new React Native project called "ActivityFeedExample":

expo init -t blank --name activity-feed-example cd activity-feed-example expo install expo-activity-feed expo-permissions expo-image-picker

This will create the skeleton of the project and install the React Native Activity feed library

Add Stream to your application

Now that we have a project ready, let's add the initial configuration to use Stream's APIs

Open App.js in your text editor of choice and make the following changes:

Step-1

import React from 'react'; import { SafeAreaView } from 'react-native'; import { StreamApp } from 'expo-activity-feed'; const App = () => { return ( <SafeAreaView style={{ flex: 1 }}> <StreamApp apiKey='YOUR_API_KEY' appId='APP_ID' token='USER_TOKEN' /> </SafeAreaView> ); }; export default App;

Your application is now configured with the API credentials for the demo application. StreamApp is going to be the parent element for all other components and manages current user's session (token) and your Stream application API credentials (apiKey and appId).

Because this is a tutorial, we do not have a real signup flow and we will use a pre-generated user session token, on a real-world application, your authentication backend would generate such token at log-in / signup and hand it over to the mobile app.

This is how you would generate the token server side (no need to do this for this tutorial):

// npm install getstream --save

let stream = require('getstream');

let client = stream.connect('YOUR_API_KEY', 'YOUR_API_SECRET');
let userToken = client.createUserToken('USER_ID');

To preview the application, you will need to install the Expo app on your phone and connect to WiFi so that you are on the same network as your computer. If you have Android Studio or Xcode you can also preview the application using the built-in emulator.

yarn start

This will start the React Native development server, you can leave it running, it will live reload your news feed application when you make code changes.

Timeline Feed

The example news feed is loaded with some demo data, this way you can see how different kinds of activities are rendered out of the box.

Adding a timeline feed to your app is very simple, the library comes with a built-in FlatFeed component which loads the current user's timeline using the APIs and renders its content.

Step-2

import React from 'react'; import { SafeAreaView } from 'react-native'; import { StreamApp, FlatFeed } from 'expo-activity-feed'; const App = () => { return ( <SafeAreaView style={{ flex: 1 }}> <StreamApp apiKey='YOUR_API_KEY' appId='APP_ID' token='USER_TOKEN'> <FlatFeed /> </StreamApp> </SafeAreaView> ); }; export default App;

Your application will now reload and show the newsfeed. Pagination included as well as Open-Graph, hashtags, mentions and image rendering.

All it took here was adding the FlatFeed component which renders the timeline feed for the user configured in StreamApp parent element.

<FlatFeed feedGroup='timeline' userId='USER_ID' />

This is how the FlatFeed element would look like if we were not using the defaults provided by the parent StreamApp element.

Like Button

Let's make our first customization to the timeline feed and show a like button under each activity. The library has a LikeButton component that integrates with the feed and we are going to add it by changing the layout of feeds' activities.

The Activity component rendering is divided in three parts: Header, Content and Footer. Each of these sections can be changed via a prop. In this case we are replacing the footer (which is empty by default) with LikeButton:

Step-3

<Activity {...props} Footer={<LikeButton {...props} />} />

The FlatFeed component has a prop called Activity that allows you to change how activities are rendered, in our case we will pass the function returning our custom activity element defined above.

import React from 'react'; import { SafeAreaView } from 'react-native'; import { StreamApp, FlatFeed, Activity, LikeButton } from 'expo-activity-feed'; const CustomActivity = (props) => { return <Activity {...props} Footer={<LikeButton {...props} />} />; }; const App = () => { return ( <SafeAreaView style={{ flex: 1 }}> <StreamApp apiKey='YOUR_API_KEY' appId='APP_ID' token='USER_TOKEN'> <FlatFeed Activity={CustomActivity} /> </StreamApp> </SafeAreaView> ); }; export default App;

Status Update

Now that we have managed to read your timeline and add a likes to it, let's add a status update screen so that we can add new activities ourselves.

For this we can use the StatusUpdateForm which comes with image upload and open-graph support. We can add this at the bottom of the render method and it will automatically fit with the rest of the UI.

import React from 'react'; import SafeAreaView from 'react-native-safe-area-view'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { StreamApp, FlatFeed, Activity, LikeButton, StatusUpdateForm } from 'expo-activity-feed'; const CustomActivity = (props) => { return <Activity {...props} Footer={<LikeButton {...props} />} />; }; const App = () => { return ( <SafeAreaProvider> <SafeAreaView style={{ flex: 1 }}> <StreamApp apiKey='YOUR_API_KEY' appId='APP_ID' token='USER_TOKEN'> <FlatFeed Activity={CustomActivity} /> <StatusUpdateForm feedGroup='timeline' /> </StreamApp> </SafeAreaView> </SafeAreaProvider> ); }; export default App;

The built-in StatusUpdateForm component does several things out-of-the-box for you:

url-previews

URL Previews

Whenever you paste or insert a URL, a preview of the page will be fetched from Stream's APIs and presented in a preview box. Try copy/paste https://goo.gl/Hok8hp in the form to see it in action.


image-upload

Image Uploads

Upload images directly from your Camera Roll.


post-to-feed

Post to user feed

Once the form is submitted, an activity is created and added to the same feed. You can scroll down the feed to load the new activity.

Realtime updates

see-new-activity

As a final touch, we are connecting the timeline to Stream's realtime APIs so that we can show a message each time a new activity is added to the feed. In this case we don't have to add a new component but only enable FlatFeed's built-in pager using the notify prop.

Step-4

import React from 'react'; import SafeAreaView from 'react-native-safe-area-view'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { StreamApp, FlatFeed, Activity, LikeButton, StatusUpdateForm } from 'expo-activity-feed'; const CustomActivity = (props) => { return <Activity {...props} Footer={<LikeButton {...props} />} />; }; const App = () => { return ( <SafeAreaProvider> <SafeAreaView style={{ flex: 1 }}> <StreamApp apiKey='YOUR_API_KEY' appId='APP_ID' token='USER_TOKEN'> <FlatFeed Activity={CustomActivity} notify /> <StatusUpdateForm feedGroup='timeline' /> </StreamApp> </SafeAreaView> </SafeAreaProvider> ); }; export default App;

Server-side Integration

So far we looked at how you can read and post activities using React Native. In most cases you will also need to perform server-side interactions such as creating follow relationships, adding activities or change user-data. All the functionality we looked at in this tutorial is exposed via Stream's REST API and can be used server-side.

This is how we can add an activity from server-side:

// npm install getstream --save
// let stream = require('getstream');

let client = stream.connect('YOUR_API_KEY', 'YOUR_API_SECRET');

let feed = client.feed('timeline', 'USER_ID');
feed.addActivity({
    'actor': client.user('USER_ID').ref(),
    'verb': 'post',
    'object': 'I love this picture',
    'attachments': {
        'og': {
            'title': 'Crozzon di Brenta photo by Lorenzo Spoleti',
            'description': 'Download this photo in Italy by Lorenzo Spoleti',
            'url': 'https://unsplash.com/photos/yxKHOTkAins',
            'images': [
                {
                    'image': 'https://goo.gl/7dePYs'
                }
            ]
        }
    }
})

Final Thoughts

In this tutorial we saw how easy it is to use Stream API and the React Native library to add a fully featured timeline to an application.

Adding feeds to an app can take weeks or months, even if you're a React Native developer. Stream makes it easy and gives you the tools and the resources to improve user engagement within your app. Time to add a feed!

Give us Feedback!

Did you find this tutorial helpful in getting you up and running with React Native for adding feeds to your project? Either good or bad, we’re looking for your honest feedback so we can improve.