How to Build A Feed App With React and Tailwind CSS
Tags: react, css
Published: 2020-02-02 08:47:27

A feed app is a simple app that curates the latest news and articles all over the web and different sources. 

So in this article, I will explain how to simply create one using React, Tailwind CSS and my Feed API (https://medrum.herokuapp.com). At the end of this article, we'll be able to build something similar to this - https://ey6n5.csb.app/

If you want a live and hands-on experience, you can follow the video below:

{% youtube 9b7rzrjHLKo %}

Subscribe to my channel here: https://bit.ly/oyetoketoby

If you are not able to watch the video, you can simply continue reading on below.

# Prerequisites

1. CRA (react)
2. Axios (http)
3. Tailwind CSS (CDN) (not necessary)

# Setting Up Our Project

The first step here is to set up our react project using Create-React-App. If you don't have it installed, you can read about the installation process [here](https://create-react-app.dev/docs/getting-started).

To create our app, simply run the command below:

```bash
$ npx create-react-app feed-app
```

After successfully creating our CRA app, let's get into other setups.

Navigate to the `src` folder in the main directory and create:

1. A `components` folder. Then in the `components` folder, create three files (`sidebar.js`, `main.js`, `articles.js`).
2. a `config.js` file

```bash
$ mkdir components
$ touch config.js components/sidebar.js components/main.js components/articles.js
```

The next thing is to add the Tailwind CSS to your project. There are many ways to do this, but the easiest and fastest way is to use the CDN. You can head over [here](https://tailwindcss.com/docs/installation/#using-tailwind-via-cdn) to get the CDN or simply use the one below:

```bash
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
```

Now in the `public` folder, open the `index.html` and update it with the Tailwind CSS.

# Feed API - Understanding How Medrum API Works

Before we proceed into coding and the next phase of the project, let's try to understand how the Feed API works. Medrum is built using Python, BeautifulSoup, and Scrapy to scrape articles, news and other various things on the internet.

Medrum has two endpoints, `articles` and `feeds`. In articles, you can't really specify which source you want to read from, but you can from feeds.

Basically, to get latest articles, you can send a request to this endpoint - https://medrum.herokuapp.com/articles/ which would return something like below:

```json
[{"title": "Juno Makes Writing Julia Awesome", "url": "https://towardsdatascience.com/juno-makes-writing-julia-awesome-f3e1baf92ea9", "comment_url": null, "ago": "3h", "date": "2020-02-02 04:06:09AM UTC"}, {"title": "Introducing Leya: The Meta-Statistical Lisp-like language", "url": "https://towardsdatascience.com/introducing-leya-the-meta-statistical-lisp-like-language-ef9012affbdb", "comment_url": null, "ago": "8h", "date": "2020-02-01 11:26:32PM UTC"}, {"title": "Transform Reality with Pandas", "url": "https://towardsdatascience.com/transform-reality-with-pandas-96f061628030", "comment_url": null, "ago": "10h", "date": "2020-02-01 09:34:26PM UTC"}, {"title": "Using Stringr and Regex to Extract Features from Textual, Alphanumeric  and Punctuation Data in R", "url": "https://towardsdatascience.com/using-stringr-and-regex-to-extract-features-from-textual-alphanumeric-and-punctuation-data-in-r-2565256c0a77", "comment_url": null, "ago": "13h", "date": "2020-02-01 06:31:13PM UTC"}, {"title": "Getting Browser User Permission with the Permissions API", "url": "https://levelup.gitconnected.com/getting-browser-user-permission-with-the-permissions-api-eafbc9c7f4d7", "comment_url": null, "ago": "15h", "date": "2020-02-01 04:03:06PM UTC"}, {"title": "Get More Out of Google Colab", "url": "https://medium.com/analytics-vidhya/get-more-out-of-google-colab-5bf9d9519a56", "comment_url": null, "ago": "16h", "date": "2020-02-01 03:34:54PM UTC"}]
```

You can filter the intervals of the articles scraped. It can either be `latest`, `day`, `week`, `month`. For instance, you can get all articles posted this week using - https://medrum.herokuapp.com/articles/?interval=week.

To be able to get a feed, you must specify a source id, which can be found here - https://medrum.herokuapp.com/sources/

To get `dev.to` feeds, you'd need to use the dev.to source id (`5bbb1af8af62ff6841b4b26e`) in the combination below:

```
https://medrum.herokuapp.com/feeds/?source=5bbb1af8af62ff6841b4b26e&page=1&sort=popular
```

You can filter the endpoints using `page` and `sort` (`popular`, `latest`).

Cool right and it's free to use.

You can support me on Patreon - https://www.patreon.com/oyetoketoby to continue building free APIs

# Building Our Feed Application

Now that we have understood how the API works, let's see how to incorporate this into our app. 

Open the `config.js` file:

```js
export const SOURCES_URL = "https://medrum.herokuapp.com/sources/"
export const FEEDS_URL = "https://medrum.herokuapp.com/feeds"
```

This contains the two endpoints we'll be using in our application.

Now open the `main.js` file and paste the below:

```jsx
import React, { useState, useEffect } from "react";

import Sidebar from "./sidebar";
import Articles from "./articles";
import { SOURCES_URL, FEEDS_URL } from "../config";

import axios from "axios";

function Main() {
  const [sources, setSources] = useState([]);
  const [articles, setArticles] = useState([]);
  const [source, setSource] = useState([]);

  
  const fetchSource = id => {
    setSource(id);
    setArticles([]);
    axios.get(`${FEEDS_URL}?source=${id}`).then(res => {
      setArticles(res.data);
    });
  };
  useEffect(() => {
    axios.get(SOURCES_URL).then(res => {
      setSources(res.data);
    });
    fetchSource("5718e53d7a84fb1901e05914");
  }, []);
  return (
    <div className="flex">
      <div className="w-1/4 bg-gray-500 p-3">
        <Sidebar source={source} sources={sources} fetchSource={fetchSource} />
      </div>
      <div className="w-3/4 bg-gray-400 p-3">
        <Articles articles={articles} />
      </div>
    </div>
  );
}

export default Main;
```

Here's what we did above:

1. We imported our `Sidebar` and `Articles` components
2. We added three `useState` hooks - `sources`, `articles`, `source`
3. We created a function-`fetchSource`: This will be used in getting a source feeds.
4. We added a `useEffect` hooks: This will get the available sources we can get their feeds and also loads a source feed by default.
5. We passed the `source`, `sources` and `fetchSource` to the `Sidebar` component and `articles` to the `Articles` components as props

The next thing is to open the `sidebar.js` component:

```jsx
import React from "react";

function Sidebar({ sources, fetchSource, source }) {
  if (!sources.length) return <p>Loading...</p>
  
  return (
    <>
      {sources.map((s, k) => {
        if (s.contentType!=="news") return null;
        return (
          <p
          key={k}
            className="mb-3"
style={{background: s.id===source ? "#ccc": "transparent"}}
            onClick={() => {
              fetchSource(s.id);
            }}
          >
            {s.name}
          </p>
        );      
      })}
    </>
  );
}

export default Sidebar;
```

The above is actually very easy to understand, but here's the breakdown:

1. Show loading if the `sources` prop is empty
2. Map through the `sources` prop, check if the contentType of the current source is news, then display the name, add an onClick event to call `fetchSource` with the source id as param and add a background if the current source id is the active source id.

The next thing now is to open the `articles.js` file:

```jsx
import React from "react";

function Articles({ articles }) {
  if (!articles.length) return <p>Loading...</p>

  return (
    <>
      {articles.map((a, k) => {
        return (
          <p className="mb-4" key={k}>
            <a href={a.url} target="_blank">{a.title}</a>
          </p>
        );
      })}
    </>
  );
}

export default Articles;
```

In this we didn't do anything much, we only mapped through the `articles` prop to display all the feeds. 

The last thing to do is to import our `main.js` component in `app.js` file:

```jsx
import React from "react";
import "./styles.css";
import Main from "./components/main";

function App() {
  return (
    <div className="wrapper">
      <Main/>
    </div>
  );
}
```

That's it! If everything goes well, you should see something like below:

![Screen Shot 2020-02-02 at 9.29.12 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1580632524088/5n1BWVlwx.png)

That's all. You can check out a live demo here: https://ey6n5.csb.app/. You can check out the code on code sandbox here: https://codesandbox.io/s/boring-moore-ey6n5

Don't forget to share to others and if you want to support me here's my Patreon: https://www.patreon.com/oyetoketoby