React30-Part 12: Building Instagram Stories feed using React.js
Introduction
In this tutorial, we’ll create a Instagram Stories Feed using React.js. We’ll learn how to use the render categories grid and show stories with text to users.
Goal
Build a app which show 9 categories to users as shown below:
On clicking on each category, we should show stories related to clicked category:
Try this project on your own before proceeding with solution below.
Prerequisites
- Node.js and npm installed on your system.
- Basic understanding of JavaScript and React.
Step 1: Set Up a New React App
Create a new React app using Create React App:
npx create-react-app insta-stories-feed
cd insta-stories-feed
Step 2: Install Dependencies
Install required dependencies react-insta-stories
and react-router-dom
npm install react-insta-stories react-reveal react-router-dom@5.2.0
Step 3: Create Components
Inside the src
folder, create a components
folder. Inside it, create a StoriesComponent.js
component:
import React, { useState } from "react";
import Stories from "react-insta-stories";
import { useRouteMatch, useHistory } from "react-router-dom";
import StoriesData from "../dataSource/storiesData";
import Fade from "react-reveal/Fade";
import "./StoriesComponent.css";
export default function StoriesSection() {
const [loading, setLoading] = useState(true);
const match = useRouteMatch();
const history = useHistory();
function redirectToHome() {
history.push("/");
}
function renderLoading() {
return (
<div className="flex justify-center items-center">
<svg class="loader animate-spin"></svg>
</div>
);
}
function getStoriesObject() {
const category = match.params.categoryName;
const stories = StoriesData[category].map((item) => {
if (item.type === "imageCaptionPost") {
return {
content: (props) => (
<div className="story-container bg-black w-screen h-screen flex items-start justify-center">
<div
className="w-full h-full bg-black max-w-screen-md flex items-center justify-center flex-col bg-center bg-no-repeat"
style={{ backgroundImage: `url(${item.image})` }}
>
<div
className="mt-12 caption text-5xl font-bold"
style={{ color: item.captionColor }}
>
<span>{item.caption}</span>
</div>
</div>
</div>
),
};
} else if (item.type === "titleImageTextPost") {
return {
content: (props) => (
<div
className="story-container h-screen w-screen bg-center bg-no-repeat bg-black text-white font-bold flex items-start justify-center"
style={{ backgroundColor: item.bgColor }}
>
<div className="max-w-screen-md flex items-center justify-center flex-col">
<div className="mt-10 text-x">
<span>{item.title}</span>
</div>
<div className="flex flex justify-center items-center mt-2 text-story-image-container">
<div style={{ display: loading ? "block" : "none" }}>
{renderLoading()}
</div>
<div style={{ display: loading ? "none" : "block" }}>
<img
src={item.image}
alt="stories"
className="h-6/12"
onLoad={() => setLoading(false)}
/>
</div>
</div>
<div className="mt-6 caption text-lg text-left mx-3 max-w-screen-md">
<span className="whitespace-pre-wrap">{item.text}</span>
</div>
</div>
</div>
),
};
} else {
return null;
}
});
return stories;
}
return (
<div className="stories-container w-screen h-screen">
<Fade right>
<Stories
stories={getStoriesObject()}
defaultInterval={5000}
width={"100%"}
height="100vh"
onAllStoriesEnd={redirectToHome}
onStoryEnd={() => setLoading(true)}
/>
</Fade>
</div>
);
}
Here we are showing stories based data souce type using react-insta-stories
npm.
Create StoriesComponent.css
file:
.story-container {
background: white;
}
.text-story-image-container {
min-height: 35vh;
}
.loader {
border: 8px solid #f3f3f3; /* Light grey */
border-top: 8px solid #3498db; /* Blue */
border-radius: 50%;
width: 50px;
height: 50px;
animation: spin 2s linear infinite;
}
Create Home.js
component within src
folder:
import React, { useState } from "react";
import "./Home.css";
import categoryItems from "../dataSource/categories";
import CreditsComponent from "./CreditsComponent";
import { useHistory } from "react-router-dom";
export default function Home() {
const [isCreditsPopUpOpen, setCreditsPopUpOpen] = useState(false);
const history = useHistory();
function redirectToStory(categoryItem) {
history.push(`/story/${categoryItem.name.toLowerCase()}`);
}
function renderCategoryItem() {
return categoryItems.map((categoryItem) => {
return (
<div
className="flex justify-center items-center flex-col mt-4 cursor-pointer"
key={categoryItem.name + categoryItem.iconName}
onClick={() => redirectToStory(categoryItem)}
>
<div className="category-outer-circle flex justify-center items-center">
<div className="category-inner-circle flex justify-center items-center">
<i className="material-icons text-4xl">{categoryItem.iconName}</i>
</div>
</div>
<div className="font-bold">{categoryItem.name}</div>
</div>
);
});
}
return (
<div>
<div className="header text-white flex justify-center items-center text-3xl font-bold">
<div>Stories Feed</div>
<div
className="fixed top-3 right-4 cursor-pointer"
onClick={() => setCreditsPopUpOpen(true)}
>
<i className="material-icons text-4xl">info</i>
</div>
</div>
<div className="flex justify-center items-center">
<div className="grid grid-cols-3 w-screen flex justify-center items-center max-w-screen-md">
{renderCategoryItem()}
</div>
</div>
{isCreditsPopUpOpen ? (
<CreditsComponent setCreditsPopUpOpen={setCreditsPopUpOpen} />
) : null}
</div>
);
}
Here we show 9 categories to user from which user can click and get redirected to stories.
Create Home.css
file:
.header {
height: 10vh;
background: #9c27b0;
font-family: "Source Sans Pro", sans-serif;
}
.category-inner-circle {
width: 95px;
height: 95px;
background: #2196f3;
border-radius: 50%;
border: 4px solid white;
}
.category-outer-circle {
width: 115px;
height: 115px;
border-radius: 50%;
background-image: linear-gradient(
253.4deg,
rgba(64, 93, 230, 0.8) 31.1%,
rgba(147, 60, 219, 0.79) 51.28%,
rgba(193, 53, 132, 0.81) 69.63%,
rgba(253, 29, 29, 0.83) 86.15%
);
background-origin: border-box;
background-clip: content-box, border-box;
}
Create CreditsComponent.js
file to show image source credits:
import React from "react";
import "./CreditsComponent.css";
export default function CreditsComponent({ setCreditsPopUpOpen }) {
function renderCreditItems() {
return (
<div className="text-left credits-text-container overflow-y-scroll">
Food1:- Image by{" "}
<a href="https://pixabay.com/users/pexels-2286921/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=1867398">
Pexels
</a>{" "}
from{" "}
<a href="https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=1867398">
Pixabay
</a>
<br />
...
</div>
);
}
return (
<div>
{/* This example requires Tailwind CSS v2.0+ */}
<div
className="fixed z-10 inset-0 overflow-y-auto"
aria-labelledby="modal-title"
role="dialog"
aria-modal="true"
>
<div className="flex items-end justify-center min-h-screen px-4 py-4 text-center sm:block sm:p-0">
<div
className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"
aria-hidden="true"
/>
<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
</span>
<div className="credits-container w-screen inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:align-middle sm:max-w-lg sm:w-full">
<div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3
className="text-lg leading-6 font-medium text-gray-900"
id="modal-title"
>
Credits
</h3>
<div className="mt-2">{renderCreditItems()}</div>
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:px-6 sm:flex justify-center items-center">
<button
type="button"
className="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"
onClick={() => setCreditsPopUpOpen(false)}
>
Go Back
</button>
</div>
</div>
</div>
</div>
</div>
);
}
Create CreditsComponent.css
:
a {
color: rgba(220, 38, 38, 1);
}
.credits-container {
height: 95vh;
}
.credits-text-container {
height: 70vh;
}
Create a dataSource
folder within src directory where create dataSource files for our stories feed app. Next create categories.js
file within the folder:
const categoryItems = [
{
name: "Tech",
iconName: "computer",
},
{
name: "Travel",
iconName: "map",
},
{
name: "Food",
iconName: "restaurant",
},
{
name: "Entertainment",
iconName: "live_tv",
},
{
name: "Science",
iconName: "poll",
},
{
name: "Fitness",
iconName: "fitness_center",
},
{
name: "Education",
iconName: "school",
},
{
name: "Gaming",
iconName: "videogame_asset",
},
{
name: "Social",
iconName: "comment",
},
];
export default categoryItems;
Next create storiesData.js
file with data from below file in dataSource
folder:
Make sure replace image URLs with your own image URLs. You can create an account on Cloudinary which is a free image CDN and upload your own images there.
Step 4: Use the Components in App.js
Modify src/App.js
to integrate the components:
import "./App.css";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Home from "./components/Home";
import StoriesComponent from "./components/StoriesComponent";
function App() {
return (
<div className="App">
<Router>
<Switch>
<Route path="/story/:categoryName">
<StoriesComponent />
</Route>
<Route path="/" exact>
<Home />
</Route>
</Switch>
</Router>
</div>
);
}
export default App;
Step 5: Add Tailwind CSS
Modify src/index.js
to include Tailwind CSS styles:
import "tailwindcss/dist/tailwind.css";
Alternatively you can import tailwindcss in public/index.html
:
<script src="https://cdn.tailwindcss.com"></script>
Step 6: Start the Server
In your terminal, make sure you’re in the insta-stories-feed
directory and run:
npm start
Your React app should start, and you will see an Instagram Stories Feed with categories and stories. Click on a category to view the stories for that category.
Source Code:
You can also follow video explanation for the project below:
Conclusion
By following these steps, you’ve built an Instagram Stories Feed app using React and Tailwind CSS. Feel free to customise the project further. Have a nice day ahead!
Check out my Youtube channel for more content:
Check out next part to build SpaceX Info App:-