DEV Community

Cover image for Hook Dev.to blogs to your react app
Antoine Mincy
Antoine Mincy

Posted on • Edited on

Hook Dev.to blogs to your react app

So, I love the Dev.to community and more so I love how easy it is to create a blog. So, I was looking for a way to have my blogs that I publish on here go straight to my personal site. Thankfully, this was pretty easy due to dev's api and a couple react hooks. Here is how I implemented mine on my personal site.

Contents

  1. Direct to a specific blog article
  2. List your blog articles on a page
  3. Dynamically go to a blog article from a list

In a rush? Here is the Github Repo

For the sake of time I am going to make a few assumptions here:

You are familiar with React and React Hooks
You have a basic understanding of an API
You have at least one published article on Dev.to

1. Direct to a specific blog article

Alt Text

Let's start with creating a basic react app: npx create-react-app dev-blog

Once the app is done installing let's do our usual boilerplate clean up of the App.js file. Here is mine:

function App() {

    return (
        <div>
            Dev Blog
        </div>
    );
}

export  default App;
Enter fullscreen mode Exit fullscreen mode

Now let's take a look at the api docs here. While their api is still in beta, as you can see there are several ways you can retrieve data from the site. As you explore different paths and responses you may come across a few that are not correct or not returning but I have yet to come across one and overall am pretty pleased with their work.

The path I recommend is under articles and named the A published article by path GET call. Let's add a constant named blogPath to our code and we want to set that const to https://dev.to/api/articles/{Your UserName}/{Your Article ID} Simply navigate to a blog post you want show to get that Article ID. Here is mine.

function App() {
const blogPath = 'https://dev.to/api/articles/simplymincy/test-post-2-2j8a`';
    return (
        <div>
            Dev Blog
        </div>
    );
}

export  default App;
Enter fullscreen mode Exit fullscreen mode

The next thing we want to do is make a call with that const to get the response body. To do this we can use useState and useEffect and a package commonly used with react called axios, which will be used to make our http requests. Let's go ahead and install that package npm i axios.

After that installs let's use the useState hook and set it to be our article Body response.

import React, { useEffect, useState } from  "react";
import axios from  "axios";

function App() {
const blogPath = 'https://dev.to/api/articles/simplymincy/test-post-2-2j8a`';
const [articleBody, setArticleBody] = useState();

    return (
        <div>
            Dev Blog
        </div>
    );
}

export  default App;
Enter fullscreen mode Exit fullscreen mode

To actually get that response we will need to now use useEffect and axios to make that call using the blogPath we created. It should look something like I have below with us checking for the response.data and setting that to our setArticleBody. Be sure to set a dependency here in your useEffect or this call will continuously run in the background. We only want this to update if there is a page load so we can set it dependent to the blogPath.

Axios makes it really easy to make requests. Feel free to check out their docs

import React, { useEffect, useState } from  "react";
import axios from  "axios";

function App() {
const blogPath = 'https://dev.to/api/articles/simplymincy/test-post-2-2j8a`';

const [articleBody, setArticleBody] = useState();

    useEffect(() => {
        axios.get(blogPath).then((response) => {
            setArticleBody(response.data);
        });
    }, [blogPath]);

    return (
        <div>
            Dev Blog
        </div>
    );
}

export  default App;
Enter fullscreen mode Exit fullscreen mode

Now at this point you would think we could replace the contents in the return with one of the properties we are getting in our response. I mean for sure "body_html" property should work right? Just use that and place that in the return. I am sure you know the problem with trying that but if you don't it is because that return is not real HTML. It is jsx. So, it will not do any formatting. So, instead let's go with the "body_markdown" property instead and to get the markdown formatting to show up correctly on our page we are going to use another package react-markdown. This package converts your markdown code into code jsx can understand and displays it properly. So, let's install that package and make those updates shall we:

function App() {
const blogPath = 'https://dev.to/api/articles/simplymincy/test-post-2-2j8a`';

const [articleBody, setArticleBody] = useState();

    useEffect(() => {
        axios.get(blogPath).then((response) => {
            setArticleBody(response.data);
        });
    }, [blogPath]);

    if (!articleBody) return  null;

    const markdown = articleBody.body_markdown;

    return (
        <div>
            <ReactMarkdown>{markdown}</ReactMarkdown>
        </div>
    );
}

export  default App;
Enter fullscreen mode Exit fullscreen mode

I've also added a simple check on the body response to see if it exists and to return null if it doesn't. That way our app will not crash if that path no longer exists.

At this point you should be able to see the page loaded with your article. This is pretty basic but we can do some more dynamic things with this api.

2. List a collection of articles on a page

Image description

So, first thing we want to do here is make a new component. Let's call it Article.js because this is where we will return... well our articles.

 const Article = () => {
        return ();
 };

 export  default Article;
Enter fullscreen mode Exit fullscreen mode

And since we did all that work already in our App.js file. Let's just move that over to this Article.js file.

import React, { useEffect, useState } from  "react";
import axios from  "axios";
import ReactMarkdown from  "react-markdown";

const Article = () => {

const blogPath = `https://dev.to/api/articles/simplymincy/test-post-2-2j8a`;
const [articleBody, setArticleBody] = useState();

    useEffect(() => {
        axios.get(blogPath).then((response) => {
            setArticleBody(response.data);
        });  
    }, [blogPath]);

    if (!articleBody) return  null;

const markdown = articleBody.body_markdown;

    return (  
        <div> Dev Blog
            <ReactMarkdown>{markdown}</ReactMarkdown>
        </div>
    );
};

export  default Article;
Enter fullscreen mode Exit fullscreen mode

Our App.js should be empty now and look like this:

import React from  "react";

function App() {

return (
<div>
Empty App
</div>

);

}

export  default App;
Enter fullscreen mode Exit fullscreen mode

Before we do anything else to that file let's create our collection component Collection.js with some of the same imports as before:

import React, { useEffect, useState } from  "react";
import axios from  "axios";

const Collection = () => {

return ();    
};
export  default Collection;
Enter fullscreen mode Exit fullscreen mode

And we want to retrieve the data similar to how we did with the Article component but we want to use this url https://dev.to/api/articles?username={Your UserName} to get the collection of articles instead.

import React, { useEffect, useState } from  "react";
import axios from  "axios";

const Collection = () => {
    const collectionPath = `https://dev.to/api/articles?username=simplymincy`;
    const [articleCollection, setArticleCollection] = useState();

    useEffect(() => {
        axios.get(collectionPath).then((response) => {
            setArticleCollection(response.data);
        });
    }, [collectionPath]);

    if (!articleCollection) return  null;

    return  <div>Dev Collection</div>;
};

export  default Collection;
Enter fullscreen mode Exit fullscreen mode

Since we will be getting an array of data we will use the map() method to display every element. It should look something like I have below where we are taking that articleCollection and spitting out every article (You can name that whatever you like) based on its id.

const list = articleCollection.map((article) => (

    <div  key={article.id}>
        Data we want to display here
    </div>
));
    return (
        <div>Dev Collection
            {list}
        </div>
    );
Enter fullscreen mode Exit fullscreen mode

I also want to display an image and the title of the article so I will add a couple more but feel free to add whatever you like here based off the api.

import React, { useEffect, useState } from  "react";
import axios from  "axios";

const Collection = () => {
    const collectionPath = `https://dev.to/api/articles?username=simplymincy`;
    const [articleCollection, setArticleCollection] = useState();

        useEffect(() => {
            axios.get(collectionPath).then((response) => {
                setArticleCollection(response.data);
            });
        }, [collectionPath]);

    if (!articleCollection) return  null;
    const list = articleCollection.map((article) => (

        <div  key={article.id}>
            <div>
                <div>
                    <img  src={article.social_image}  alt="Article Images"  />
                </div>
                    <div>
                        <h4>{article.title}</h4>
                    </div>
                </div>
            </div>
        ));

    return (

        <div>
            Dev Collection
            {list}
        </div>
    );
};

export  default Collection;
Enter fullscreen mode Exit fullscreen mode

Let's now import the Collection component in our App.js file

import React from  "react";
import Collection from  "./Collection";

function App() {

    return (
        <React.Fragment>
            <Collection/>
        </React.Fragment>
    );
}

export  default App;
Enter fullscreen mode Exit fullscreen mode

We should now see a collection of our published articles on our page. Now the last thing we want to do (besides adding some css to have it more appeasing on our eyes) is have each article clickable and navigate to that particular article onClick. Let's do that now.

3. Navigate to a blog article from a list

Image description

For this we are going to use another common package that is used with React and that is react-router-dom. So, let's install that and before we get the Collection component ready to have a clickable element we need to go to our App.js file and make a few changes. Right now our app is a single page app. Being that we will at the very least now have 2 pages we can now navigate, we need to set up some routes. This is a decent enough change so for this one I am going to show the fully updated App.js file and then explain.

import React from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Article from "./Article";
import Collection from "./Collection";

function App() {
  return (
    <React.Fragment>
      <BrowserRouter basename={"/"}>
        <Switch>
          <Route
            exact
            path={`${process.env.PUBLIC_URL}/`}
            component={Collection}
          />
          <Route
            exact
            path={`${process.env.PUBLIC_URL}/Article/simplymincy/:path`}
            component={Article}
          />
        </Switch>
      </BrowserRouter>
    </React.Fragment>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

I am now using the react-router-dom package in our most top level component because I want to set up the different routes I spoke of before. Hence why we are using the BrowserRouter, Switch, and Route methods. The BrowserRouter tag is used to push, replace, and pop the various return states we will now have in our app. Inside of that we set a Switch tag which works very similiar to a switch statement meaning that it returns the first child it has that matches a location and as you can see we have 2 Route tags. There are a lot of properties you can set for these and I highly recommend looking over the docs here, but for my example I am checking for an exact match on the path property and I am setting the components to the 2 components we created earlier. Looking closer you will see that I have the Collection component set as my base url and the route with the Article component with a more unique path. The /Article/simplymincy/ was simply what I chose here but you can have your path be anything as long as it is unique.

Last thing, I want to point out here is the :path piece you see in that url. We use this here so that when we do eventually click on a link in our Collection component we will pass it some parameters. We do that by importing react-router-dom to our component and using the Link method. Think of this as an <a> tag. Here is the updated file now:

    import React, { useEffect, useState } from  "react";
    import axios from  "axios";
    import { Link } from  "react-router-dom";

    const Collection = () => {
        const collectionPath = `https://dev.to/api/articles?username=simplymincy`;

        const [articleCollection, setArticleCollection] = useState();

        useEffect(() => {

            axios.get(collectionPath).then((response) => {
                setArticleCollection(response.data);
            });
        }, [collectionPath]);

        if (!articleCollection) return  null;

        const list = articleCollection.map((article) => (

            <div  key={article.id}>
                <div>
                    <div>
                        <img  src={article.social_image}  alt="Article Images"  />
                    </div>
                    <div>
                        <h4>{article.title}</h4>
                    </div>
                </div>
                <div>
                    <Link  to={`/Article/simplymincy/${article.slug}`}>Read</Link>
                </div>
            </div>
        ));

    return (

        <div>

            Dev Collection
                {list}
        </div>
        );
    };

    export  default Collection;
Enter fullscreen mode Exit fullscreen mode

As you will notice in the Link tag we are using the same url that we set in the Article route in the App.js file. That is key, because remember we are using exact match here. If they do not match it will not return our Article component. Which leads us to our last step. Remember when we set the :path in our Article route well we did that so we can set some value and pass it through our components freely. In this case we are going to use a value we get from our api call, which is slug. This by the definition of the dev.to api is used to uniquely identify the articles users create. This is not only perfect to have our urls be unique but also will be able to get passed through so our Article component can make a direct call on that path to gets its blog content. This update is rather small. We just want to import { useParams } from "react-router-dom"; and then replace our blogPath const with this:

    const params = useParams();
    const blogPath = `https://dev.to/api/articles/simplymincy/${params.path}`;
Enter fullscreen mode Exit fullscreen mode

What we are doing here is passing in the parameters from the link we clicked on in the Collection component and we will set that slug to be the end of our blogPath. That way no matter what article we click on, it will know which one to retrieve its content for and display.

AND THATS IT!

At this point you should have all of your articles in a collection displaying and be able to click and display each article dynamically. With the API you can do a lot more such as GET and POST comments, likes, and other useful stats pertaining to your blog. I did not add any styling in here either. I leave that up to you. Here is an example of how I implemented mine.

From my personal site
Image description

Top comments (0)