Setup
In order to run the code from this tutorial on your laptop, you need to have Node 8 (or higher) and Yarn installed.
Run the following commands to create a new react app:
1234npx create-react-app react-feeds-example cd react-feeds-example npm install react-activity-feed npm start
You can also skip the setup and follow the tutorial without coding, you can see every step in action on CodePen; we have already set up an app for you and prefilled all the code examples with your credentials.
User Token
With a live application, you generate tokens server-side or with serverless functions. You don't have to do so to follow this tutorial, but the following is what the generated token might look like:
12let client = stream.connect('YOUR_API_KEY', 'YOUR_API_SECRET'); let userToken = client.createUserToken('USER_ID');
This is how you would generate the token server side (no need to do this for this tutorial):
123456// npm install getstream --save let stream = require('getstream'); let client = stream.connect('YOUR_API_KEY', 'YOUR_API_SECRET'); let userToken = client.createUserToken('USER_ID');
123456# pip install stream-python import stream client = stream.connect('YOUR_API_KEY', 'YOUR_API_SECRET', location='us-east') user_token = client.create_user_token('USER_ID')
12345678910# gem install "stream-ruby" # gem install "stream-ruby" # or add this to your Gemfile and then run bundler # gem "stream-ruby" require 'stream' client = Stream::Client.new('YOUR_API_KEY', 'YOUR_API_SECRET', :location => 'us-east') user_token = client.create_user_session_token('USER_ID')
1234// composer require get-stream/stream $client = new GetStreamStreamClient('YOUR_API_KEY', 'YOUR_API_SECRET'); $userToken = client->createUserSessionToken('USER_ID');
Add Stream to your application
For the purposes of this tutorial, we’ve prepared an app with some sample data. The StreamApp React component connects to Stream with the API key, App ID and user token. The code below connects your app to Stream. Everything you add within has access to Stream.
Open up src/App.js and replace its contents with the following code:
1234567891011import React from 'react'; import { StreamApp } from 'react-activity-feed'; import 'react-activity-feed/dist/index.css'; class App extends React.Component { render() { return <StreamApp apiKey='YOUR_API_KEY' appId='APP_ID' token='USER_TOKEN'></StreamApp>; } } export default App;
Notification Feed
To get started, we’ll add a notification feed to our app. In this example we’ll build a notification feed that’s similar to sites like Linkedin, Facebook etc. The notification feed will show which notifications are unseen/unread and update in real time.
The next piece of code adds a NotificationDropdown to our app:
123456789101112131415import React from 'react'; import { StreamApp, NotificationDropdown } from 'react-activity-feed'; import 'react-activity-feed/dist/index.css'; class App extends React.Component { render() { return ( <StreamApp apiKey='YOUR_API_KEY' appId='APP_ID' token='USER_TOKEN'> <NotificationDropdown notify /> </StreamApp> ); } } export default App;
We’ve now added a notification feed to the page.
Real-time
We made it super simple to notify your users when new updates are added to a feed. Just add the notify prop to either the FlatFeed, NotificationFeed or the above NotificationDropdown. This is all you need to do to connect your app to Stream’s Real-time API. We've gone ahead and added the notify prop to all examples in this tutorial.
Timeline Feed
Now that we have a simple notification feed in place lets see how easy it is to add an news feed/activity feed. The FlatFeed component displays your activities in a simple default styling, but you can customize this or build your own custom activity component and include it in the Activity prop.
Replace the code in src/App.js with the following example:
12345678910111213141516import React from 'react'; import { StreamApp, NotificationDropdown, FlatFeed } from 'react-activity-feed'; import 'react-activity-feed/dist/index.css'; class App extends React.Component { render() { return ( <StreamApp apiKey='YOUR_API_KEY' appId='APP_ID' token='USER_TOKEN'> <NotificationDropdown notify /> <FlatFeed notify /> </StreamApp> ); } } export default App;
We’ve now added a notification feed to the page. It may not seem like much, but try clicking the following button and see what happens.
The functionality that comes from using our React Components in conjunction with a Stream-powered FlatFeed is a great way to get started with building an application, as it offers ways of displaying several application-centric features, such as a gallery view, a card view for websites, and a third view for audio and video files, just to name a few.
Note: the FlatFeed component doesn't have infinite scrolling activated by default, but it does support it. You can turn it on by including our InfiniteScrollPaginator in the Paginator prop.
Custom Activity
In this next example you’ll learn how to customize the activity component. You can specify your own activity component using the Activity prop. The example below adds a like button to each Activity element.
12345678910111213141516171819202122232425262728import React from 'react'; import { StreamApp, NotificationDropdown, FlatFeed, Activity, LikeButton } from 'react-activity-feed'; import 'react-activity-feed/dist/index.css'; class App extends React.Component { render() { return ( <StreamApp apiKey='YOUR_API_KEY' appId='APP_ID' token='USER_TOKEN'> <NotificationDropdown notify /> <FlatFeed notify Activity={(props) => ( <Activity {...props} Footer={() => ( <div style={{ padding: '8px 16px' }}> <LikeButton {...props} /> </div> )} /> )} /> </StreamApp> ); } } export default App;
Note: you can create a (toggle) button for other types of reactions such as reposts or comments using either the ReactionIcon or the ReactionToggleIcon. These two components come preloaded with several functions to make functional reactions a breeze.
Comments
You can easily add comments to your app by adding a CommentList to the activity we started customizing. Just pass it the activityId as a prop to display all of that activity’s comments. We can do all of this in the same way as when we added the LikeButton to our activity. The other thing we need to do is tell the FlatFeed to also get the recent reactions to activities. {{ reactions: { recent:true }}
.
The CommentField allows users to post a comment. Have a look at the example below.:
123456789101112131415161718192021222324252627282930import React from 'react'; import { StreamApp, NotificationDropdown, FlatFeed, LikeButton, Activity, CommentField, CommentList } from 'react-activity-feed'; import 'react-activity-feed/dist/index.css'; class App extends React.Component { render() { return ( <StreamApp apiKey='YOUR_API_KEY' appId='APP_ID' token='USER_TOKEN'> <NotificationDropdown notify /> <FlatFeed options={{ reactions: { recent: true } }} notify Activity={(props) => ( <Activity {...props} Footer={() => ( <div style={{ padding: '8px 16px' }}> <LikeButton {...props} /> <CommentField activity={props.activity} onAddReaction={props.onAddReaction} /> <CommentList activityId={props.activity.id} /> </div> )} /> )} /> </StreamApp> ); } } export default App;
Note: You can create your own custom component for displaying lists of other types of reactions using the ReactionList component.
Status Updates
Last, but not least, we're adding a way for our users to add data to a feed.
Again, you can, of course, write your own component to post new activities. However, we, at Stream, have designed a StatusUpdateForm that does it all: emoji selection, file and image uploads, and open-graph scraping for video, audio and, of course, normal web pages. So, plenty of stuff to get started with :)
Try pasting one of the following links: https://goo.gl/Hok8hp or https://youtu.be/WKfiio7lOH0.
And we do all of this with just one extra line of code:
1234567891011121314151617181920212223242526272829303132333435363738394041import React from 'react'; import { StreamApp, NotificationDropdown, FlatFeed, LikeButton, Activity, CommentList, CommentField, StatusUpdateForm, } from 'react-activity-feed'; import 'react-activity-feed/dist/index.css'; class App extends React.Component { render() { return ( <StreamApp apiKey='YOUR_API_KEY' appId='APP_ID' token='USER_TOKEN'> <NotificationDropdown notify /> <StatusUpdateForm /> <FlatFeed options={{ reactions: { recent: true } }} notify Activity={(props) => ( <Activity {...props} Footer={() => ( <div style={{ padding: '8px 16px' }}> <LikeButton {...props} /> <CommentField activity={props.activity} onAddReaction={props.onAddReaction} /> <CommentList activityId={props.activity.id} /> </div> )} /> )} /> </StreamApp> ); } } export default App;
Please note that this tutorial uses anonymous functions (in
Activity.Footer
and alike) to portray the possibility of using components to access render properties. Refrain from using anonymous function in your production code to reduce the amount of unnecessary re-renders. If you don’t need to access render properties at all, use plain JSX element possibly wrapped inReact.Fragment
.
Server-Side Integration
So far, we’ve looked at how you can read and post activities using React. In most cases, you will also need to perform server-side interactions, such as creating follow relationships, adding activities or changing user-data. All of 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:
1234567891011121314151617181920212223// 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' } ] } } });
12345678910111213141516171819202122232425# pip install stream-python import stream client = stream.connect('YOUR_API_KEY', 'YOUR_API_SECRET') feed = client.feed('timeline', 'USER_ID') feed.add_activity({ "actor": client.users.create_reference('USER_ID'), "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" } ] } } })
12345678910111213141516171819202122232425# gem install "stream-ruby" require 'stream' client = Stream::Client.new('YOUR_API_KEY', 'YOUR_API_SECRET') feed = client.feed('user', 'USER_ID') feed.add_activity({ actor: client.collections.create_user_reference('USER_ID'), 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' } ] } } })
12345678910111213141516171819202122// composer require get-stream/stream $client = new GetStream\Stream\Client('YOUR_API_KEY', 'YOUR_API_SECRET'); $feed = $client->feed('user', 'USER_ID'); $feed->addActivity([ 'actor' => $client->collections()->createUserReference('USER_ID'), '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' ] ] ] ] ]);
12345678910111213141516// See installation details at https://github.com/GetStream/stream-java Client client = Client.builder("YOUR_API_KEY", "YOUR_API_SECRET").build(); FlatFeed feed = client.flatFeed("timeline", "USER_ID"); feed.addActivity(Activity.builder() .actor(Enrichment.createUserReference("USER_ID")) .verb("post") .object("I love this picture") .extraField("attachments", ImmutableMap.of("og", new ImmutableMap.Builder<String, Object>() .put("title", "Crozzon di Brenta photo by Lorenzo Spoleti") .put("description", "Download this photo in Italy by Lorenzo Spoleti") .put("url", "https://unsplash.com/photos/yxKHOTkAins") .put("images", Lists.newArrayList(ImmutableMap.of("image", "https://goo.gl/7dePYs"))) .build())) .build()).join();
123456789101112131415161718192021222324252627282930313233import ( stream "gopkg.in/GetStream/stream-go2.v1" ) client, err := stream.NewClient("YOUR_API_KEY", "YOUR_API_SECRET") if err != nil { // ... } feed := client.FlatFeed("user", "USER_ID") _, err = feed.AddActivity(stream.Activity{ Actor: client.Collections().CreateUserReference("USER_ID"), Verb: "post", Object: "I love this picture", Extra: map[string]interface{}{ "attachments": map[string]interface{}{ "og": map[string]interface{}{ "title": "Crozzon di Brenta photo by Lorenzo Spoleti", "description": "Download this photo in Italy by Lorenzo Spoleti", "url": "https://unsplash.com/photos/yxKHOTkAins", "images": []interface{}{ map[string]string{ "image": "https://goo.gl/7dePYs", }, }, }, }, }, }) if err != nil { // ... }
1234567891011121314151617181920212223242526272829// dotnet add package stream-net var client = new Stream.StreamClient("YOUR_API_KEY", "YOUR_API_SECRET"); var feed = client.Feed("timeline", "USER_ID"); var user = Stream.Users.Ref("USER_ID"); var activity = new Stream.Activity(Stream.Users.Ref("USER_ID"), "post", "i love this picture"); var ogData = new Dictionary<string, object>() { {"title", "Crozzon di Brenta photo by Lorenzo Spoleti"}, {"description", "Download this photo in Italy by Lorenzo Spoleti"}, {"url", "https://unsplash.com/photos/yxKHOTkAins"}, {"images", new Dictionary<string, string>[] { new Dictionary<string, string>() { {"image", "https://goo.gl/7dePYs"} } } } }; var attachment = new Dictionary<string, object>() { {"og", ogData} }; activity.SetData("attachments", attachment); await feed.AddActivity(activity);
Concluding the React Activity Feed Tutorial
In the last few minutes you’ve build a fully functional activity feed and notification feed. It includes listening to changes in real time, rich link previews using open graph scraping, file uploads, likes and comments.
All of the components are customizable. The example showed a social feed, but you can also use this to show activity related to your sales leads, notification about your business processes or you’re friends going for a run.
Stream’s API is used by over half a billion end users. The API tutorial and the docs help you take a deep dive and learn how to fully customize your activity feed’s behaviour.
Final Thoughts
In this tutorial we saw how easy it is to use Stream API and the React 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 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!