Featuring Medium Articles in React Application
While building my portfolio site, I thought it would be good to feature my Medium articles on it. I envisioned the article links to appear as snippets that look like actual Medium article links. I also wanted the component to auto-update so I don’t have to manually edit the site every time I publish a new article.
How it works
Step 1: Retrieving article data
The Medium API is not intended for post retrieval, so I had to retrieve the RSS feed via a GET request to https://medium.com/feed/@your_profile
and then convert it to JSON format using existing JavaScript libraries. I tried a few libraries, and the one that worked for me was the rss-parser library.
In the process, I encountered the cors policy no ‘access-control-allow-origin’ error, and had to add https://api.allorigins.win/raw?url= in front of the GET url to bypass it.
I also used the useEffect Hook to fetch data every time the component mounts. This ensures that the component data stays up to date.
Step 2: Styling the snippet
The CSS code (for styling) is as follows:
.long-card {
width: 100%;
min-height: 100px;
border: 0.1px solid #343a40;
text-align: left;
color: #afafaf;
display: flex;
margin-bottom: 10px;
}.long-card:hover {
text-decoration: none;
color: #afafaf;
}.long-card:hover .title {
color: #AACCFF;
text-decoration: underline
}.long-card .title {
font-size: 1rem;
font-weight: 600;
color: white;
transition: color 0.2s;
}.long-card-body {
padding: 40px 30px;
}.remarks {
font-size: 0.9rem;
}
Putting it all together, in the component’s JavaScript file,
import React, { useState, useEffect } from ‘react’;
import * as Parser from ‘rss-parser’;export default function Articles() {
const [articles, setArticles] = useState([])useEffect(() => {
async function getFeed() {
let parser = new Parser();
const rss = await parser.parseURL(‘https://api.allorigins.win/raw?url=https://medium.com/feed/@huishun');
setArticles(rss.items)
}
getFeed()
}, []);return (
<div className=”articles container-fluid section”>
<h2 className=”section-header”>WRITINGS</h2>
<div className=”section-body section-width”>
{articles.map((article, index) => (
<a href={article.guid} target=”_blank” rel=”noopener noreferrer” className=”long-card” key={index}>
<div className=”long-card-body”>
<h5 className=”title”>{article.title}</h5>
<p className="remarks">{article['content:encodedSnippet'].substring(0, 197)}...</p>
<div className=”remarks”>medium.com</div>
</div>
</a>
))}
</div>
</div>
)
}
Conclusion
The live version can be found in my portfolio site here, and the full code including other parts of the portfolio site is hosted here.