The React Blog Series: Part Two -------------------------------  This article is part two in a weekly series on building a blog with React and is an extension of the code created in part one. #### **The React Blog Series** [**Part One:** Building a website with React and Bulma](https://medium.com/front-end-hacking/building-a-website-with-react-and-bulma-d655214bff2a) **Part Two:** Building a Blog with React and Contentful [**Part Three:** Import your Medium Feed into React](https://medium.com/@aaron.klaser/import-your-medium-feed-into-react-ceadbaf785c7) [**Part Four:** Adding a Redux to a React Blog](https://medium.com/@aaron.klaser/adding-redux-to-a-react-blog-97f5fea606c2) [**Part Five:** Replacing Redux Thunks with Redux Sagas](https://hackernoon.com/replacing-redux-thunks-with-redux-sagas-4aa306854925) **Part Six:** (_In Progress_) Writing Unit Test for a React Blog with Redux Sagas This will go over the basics of setting up Contentful and displaying its data as a blog feed in our React application. > This does **not** include Redux… yet ;) ### Contentful #### Sign up for Contentful Click here to [Sign Up Here](https://www.contentful.com/sign-up/) When you start poking around Contentful, you might get a strange failure feeling, daja vue perhaps, or is it just that it looks exactly like the Wordpress Admin? **Contentful** is very clean, easy to navigate, and it looks and feels _a lot_ like Wordpress. As much as hate to admit, I love it and thats an amazing thing because I _loth Wordpress_. To be fair, I don’t hate Wordpress for its UX, I hate it because its slow and built on what looks like hacked together PHP, and lets face it, no one actually likes PHP. Not even the creator of PHP. #### The Concept **Contentful** is content management as a service (CaaS), this replaces the need to have to connect your site to that terrible MySQL database hosted on some crappy Apachy Server, where you have to install phpMyAdmin and spend hours trying to figure out cPanel. #### The Data There are two parts to your data, the structure and the data. It’s basically a really nice web form the converts to simple json. You have to first set up your form the in **_Content Model_**, then you can hop over to **_Content_** and fill out your forms, each form becomes an item in the models array of data sent via rest end points. #### Let start by making a Blog Model Add in three fields: Title, Path, and Content  The JSON preview will look like this  Now let’s create a Blog post for the app to pull and display on our Blog page. Go to Content, and Click Add Blog in the top corner and fill out the form.  Now you have your first blog post! ### Get Api Token You will need a **Space Id** and access token to retrieve your data. Go to the **APIs** tab and click **Add Api Key.** Name it what ever you want and save.  ### Set Up Contentful in React npm install contentful Let’s just see if we can connect and get our data. On `src/index.js` let’s import Contentful, set up a simple client and then getEntries. Now let’s console log what we get, with any luck we should be see our test blog post. This is temporary. import React from 'react'; import ReactDOM from 'react-dom' import registerServiceWorker from './registerServiceWorker' import { BrowserRouter as Router } from 'react-router-dom' **import \* as contentful from 'contentful'** import App from './App' import './index.css' **var client = contentful.createClient({ space: 'qu10m4oq2u62', accessToken: 'f4a9f68de290d53552b107eb503f3a073bc4c632f5bdd50efacc61498a0c592a' })** **client.getEntries().then(entries => { entries.items.forEach(entry => { if(entry.fields) { console.log(entry.fields) } }) })** ReactDOM.render(( <Router> <App /> </Router> ), document.getElementById('root')) registerServiceWorker() Run your app and open your console. You should see a little clean object full our data.  Isn’t that amazing. It was like, the simplest thing to set up ever! But now let’s do it right… well, as much as we can without Redux :P ### Setting Up Your Blog Page Copy all of your Contentful stuff and delete it from your index. Head over to your `Blog.js` and change it from a dumb component to a smart React.Component class. Then, we will need to include state with an empty post array. Paste in your Contentful createClient object. Next, using the **React** lifecycle hook **componentDidMount**, we need to call a **fetchPosts** function which will call a **setPosts** function import React from 'react' import \* as contentful from 'contentful' class Blog extends React.Component { state = { posts: \[\] } client = contentful.createClient({ space: 'qu10m4oq2u62', accessToken: 'f4a9f68de290d53552b107eb503f3a073bc4c632f5bdd50efacc61498a0c592a' }) componentDidMount() { this.fetchPosts().then(this.setPosts); } fetchPosts = () => this.client.getEntries() setPosts = response => { this.setState({ posts: response.items }) } render() { return ( <p>This is the Blog Page</p> ) } } export default Blog If you plug a console log in the **fetchPosts** function you will see we are getting our data back from **Contentful**. Now that we are getting data and we are doing it the React way (w/o Redux), let’s update the render function to display the data. We will move these to their own pretty component later, but for now let’s stick it in some pre tags. render() { return ( <div> <p>This is the Blog Page</p> <br/> { this.state.posts.map(({fields}, i) => <pre key={i}>{JSON.stringify(fields, null, 2)}</pre> )} </div> ) } Yay!!! ### Adding New Blog Posts Head back over to **Contentful** and click **Content > Add Blog**, then fill out the information. You know the drill.  Click **Publish** and head get back over to your app, refresh the browser and _BLAMMO_!! There’s your second post.  ### Styling the Blog Feed We need to set up a Blog Item component. Our Blog page will contain a list of Blog Items which make up “**_the feed_**”. [Remember we are using fractal file structures](https://medium.com/front-end-hacking/building-a-website-with-react-and-bulma-d655214bff2a) and `BlogItem.js` will be a child of `Blog.js`. Since `Blog.js` is in the **app** folder, we will create a folder called **_blog_** in the **app** folder, then create our `BlogItem.js` in our newly created **blog** folder. If you’re keeping score, and following [**Fractal File Structures**](https://medium.com/front-end-hacking/building-a-website-with-react-and-bulma-d655214bff2a) correctly, our current file structure should look something like this.  #### Create BlogItem Component In `BlogItem.js`, create as simple component with **Bulma** box. We’ll pass in props which for now will be a spread of the fields from Contentful. import React from 'react' const BlogItem = (props) => ( <div className="box content"> <h1>{props.title}</h1> <p>{props.content}</p> </div> ) export default BlogItem Now, back in **Blog.js** we need update our posts map in render to return our **BlogItem** component and spread the fields as properties. render() { return ( <div> <p>This is the Blog Page</p> <br/> { this.state.posts.map(({fields}, i) => **<BlogItem key={i} {...fields} />** )} </div> ) } Refresh and there you go. But… that kind of looks _terrible_. #### Style Blog Page Let’s replace `<p>This is the Blog Page</p>` with a **Bulma Hero** for our page header. Since we will probably do this on the top of most of our pages, lets create this as a global reusable component. In our app folder, create a new folder named components. By our fractal logic this implies that these components will all exist as children of the App. > **_Spoiler alert_**: If you haven’t figured it out yet, `App.js` and it’s folder of children (`app`), will contain all our presentation logic. For now, every we do will be a child of **App**. [Later when we refactor to use **Redux**](https://medium.com/@aaron.klaser/adding-redux-to-a-react-blog-97f5fea606c2), **App** will get a sibling named `Store.js` and its folder of children (`store`) and it will contain all of our **data services** and **state**. In the **components** folder create two files, `PageHeader.js` and `PageContent.js` **PageHeader** will be a component for our Bulma Hero. We will not be including the subtitle content. This way we can do css styling or include links and pass it as a children prop. import React from 'react' const PageHeader = (props) => ( <section className={\`hero ${props.color}\`}> <div className="hero-body"> <div className="container"> <h1 className="title"> {props.title} </h1> <h2 className="subtitle"> {props.children} </h2> </div> </div> </section> ) export default PageHeader And in our `Blog.js` replace `<p>This is the Blog Page</p>` with <PageHeader color="is-info" title="Code Blog"> Your standard <strong>JavaScript</strong> programming blog, albeit, probably not very good, but I will at least try to keep it entertaining. This blog is a chronological mix of random posts on Angular, React, Functional Programming, and my <strong>project walkthroughs</strong>. </PageHeader> **PageContent** will be a styled component to confine our page to a max width and add padding and what have you. import styled from 'styled-components' const PageContent = styled.div\` margin: 0 auto; max-width: 960px; padding: 1.5rem; \` export default PageContent Ahh… now that’s much better. ### Better More Realistic Blog Posts Back in Contentful, let’s add some fields to our Blog Content Model We are going to add three new fields: * **icon:** Set appearance as **single line** * **status**: Valid as only values “IN\_PROGRESS” and not required. Set appearance as **Dropdown** * **date**: Set appearance as **date only**  Now hop over to your First and Second blog post and fill in some data. Icon can be a url link to an icon or base64 as long is it can normally go into a **src** attribute. > _Content should set as_ **_Markdown_** _so when you fill your page content it can be styled with_ **_Markdown_**_!_  Do something like this for both posts, **save**, then refresh your. It probably going to look terrible… _YUP!_ ### Rendering Markdown So lets start by addressing the elephant in the room. We need make react render the markdown as html and it needs to look… pretty. npm install react-markdown In the `BlogItem.js`, replace content <p> with the react-markdown. import React from 'react' **import \* as Markdown from 'react-markdown'** const BlogItem = (props) => ( <div className="box content"> <h1>{props.title}</h1> **<Markdown source={props.content} />** </div> ) export default BlogItem BOOM! Much better, but I would remove the H1 titles from the **Markdown** in **Contentful** and rename your **Contentful** blog posts with what the H1 title was. You will see why when we add the Icon and stuff in next. #### Adding the Icon This is just simple **Bulma**. Open your `BlogItem.js` and we are going to steal the **box media** example from **Bulma’s** website. import React from 'react' import { Link } from 'react-router-dom' import \* as Markdown from 'react-markdown' import moment from 'moment' const BlogItem = (props) => ( <div className="box"> <article className="media"> <div className="media-left"> <figure className="image is-64x64"> <img src={props.icon} alt="Image" /> </figure> </div> <div className="media-content"> <div className="content"> <h1>{props.title}</h1> <Markdown source={props.content.split(" ").splice(0,150).join(" ").concat('...')} /> </div> <div className="level"> <div className="level-left"> <Link className="level-item button is-small is-link is-outlined" to={props.path}>Read More</Link> </div> <div className="level-right"> <p className="level-item has-text-link is-size-7"> {moment(props.date).calendar(null, { sameDay: '\[Today\]', lastDay: '\[Yesterday\]', lastWeek: '\[Last\] dddd', sameElse: 'MMM Do YYYY' })} </p> </div> </div> </div> </article> </div> ) export default BlogItem Yeah, so thats it but it’s kind of busy, and to be fair I think there is some overlap with the full page blog post ### Create A BlogPost page and clean up BlogItem Hmm… If you remember correctly in our last article, Routing works off a static `<Switch>` component. But we don’t want to have to hard code our every single blog post, that kind of defeats the purpose of using Contentful as CMS. Luckily for us, **react-router-dom** has planned ahead and allows us to have path params. In `Router.js` add new route <Switch> <Route exact path='/' component={Home}/> <Route **exact** path='/blog' component={Blog}/> **<Route path='/blog/:blogPost' component={BlogPost}/>** </Switch> > **_Important:_** _This one took me a hot minute to figure our but you_ **_CAN_** **_NOT_** _include a_ **_dash_** _(-) in the parameter name. I originally had_ `_:blog-post_` _and couldn’t figure out why it looked like it was working but it_ **_wasn’t_**_._ > _It’s also important to note that you need to add_ **_exact_** _in the_ **_Blog path_**_, otherwise it will match the_ `_/blog_` _route first._ Update the `<Link …>` in our `BlogItem.js` to put the /blog/ in front of our path <Link className="level-item button is-small is-link is-outlined" **to={{ pathname: \`/blog/${props.path}\`, state: { props } }}** \> Read More </Link> But before we can test this, we need to create a BlogPost page. For now lets just do some simple <pre> displaying so we can make sure we are sending the data to the blog post as state import React from 'react' const BlogPost = (props) => ( <h1>Blog Post</h1> <pre>{JSON.stringify(props, null, 2)}</pre> ) export default BlogPost Now when we navigate to our blog post from the blog page we should see a huge object in our `<pre>` and the history object contains our state which is our blog post. #### Set Up the Blog Page Okay, before you read this and roar with rage that i clearly have no clue what I’m doing, this is not the best way to do this and object de-structuring this way can not be a best practice. This will all move to Redux in my next tutorial and which will be a WAY cleaner solution. import React from 'react' import { Link } from 'react-router-dom' import moment from 'moment' import \* as Markdown from 'react-markdown' import PageContent from './../components/PageContent' const BlogPost = ({ location: { state: { props } }}) => { return ( <PageContent> <nav className="level"> <div className="level-left"> <Link className="level-item button is-small is-link is-outlined" to="/blog">Back to Blog</Link> </div> <div className="level-right"> <p className="level-item has-text-link is-size-7"> {moment(props.date).calendar(null, { sameDay: '\[Today\]', lastDay: '\[Yesterday\]', lastWeek: '\[Last\] dddd', sameElse: 'MMM Do YYYY' })} </p> </div> </nav> <article className="media"> <div className="media-left"> <figure className="image is-64x64"> <img src={props.icon} alt="Image" /> </figure> </div> <div className="media-content"> <div className="content"> <h1>{props.title}</h1> <Markdown source={props.content} /> </div> </div> </article> </PageContent> ) } export default BlogPost #### Clean Up the Overlap Now we can look at our `BlogItem.js` and `BlogPost.js` and find out overlapping code and make them nice pretty little components. Both our pages contain a content sections with the icon and and bottom and date sections, however, the button and date sections are in different places on the two pages. Let’s first create a folder for our new components. These are share components of the **Blog** so in the blog folder create a `shared` folder, then create two files `BlogContent.js` and `BlogNav.js` import React from 'react' import { Link } from 'react-router-dom' import moment from 'moment' const BlogNav = ({ to, date }) => ( <nav className="level"> <div className="level-left"> <Link className="level-item button is-small is-link is-outlined" to={to}>Back to Blog</Link> </div> <div className="level-right"> <p className="level-item has-text-link is-size-7"> {moment(date).calendar(null, { sameDay: '\[Today\]', lastDay: '\[Yesterday\]', lastWeek: '\[Last\] dddd', sameElse: 'MMM Do YYYY' })} </p> </div> </nav> ) export default BlogNav and import React from 'react' import \* as Markdown from 'react-markdown' const BlogContent = (props) => ( <article className="media"> <div className="media-left"> <figure className="image is-64x64"> <img src={props.icon} alt="Image" /> </figure> </div> <div className="media-content"> <div className="content"> <h1>{props.title}</h1> <Markdown source={ props.limit ? props.content.split(" ").splice(0,props.limit).join(" ").concat('...') : props.content } /> </div> { props.children } </div> </article> ) export default BlogContent In `BlogContent.js`, we won’t always use `**props.children**` but we want to put it there so we can place the nav in the that location on `BlogItems.js`. You’ll see… Now, lets update our `BlogItem.js` and `BlogPost.js`. This is gonna blow your mind. import React from 'react' import BlogNav from './shared/BlogNav' import BlogContent from './shared/BlogContent' const BlogItem = (props) => ( <div className="box"> <BlogContent limit={150} {...props }> <BlogNav date={props.date} to={{ pathname: \`/blog/${props.path}\`, state: { props } }} /> </BlogContent> </div> ) export default BlogItem > _Notice how we are wrapping the_ **_BlogNav_** _in this snippet, but not in the next one. This is what the_ **_props.children_** _is used for._ and import React from 'react' import PageContent from './../components/PageContent' import BlogNav from './shared/BlogNav' import BlogContent from './shared/BlogContent' const BlogPost = ({ location: { state: { props } }}) => ( <PageContent> <BlogNav date={props.date} to="/blog" /> <BlogContent {...props } /> </PageContent> ) export default BlogPost That’s **_SO_** much better! ### The Status Tag In my examples I am including a tag for Status, this way I can tag my posts as in progress or archived or whatever You don’t know this yet but I do plan to use this in other places so we are going to add this in the `src/components` folder. Create a file called `StatusTag.js`. import React from 'react' const StatusTag = ({status}) => { switch(status) { case 'IN\_PROGRESS': return (<span className="tag is-small is-warning" style={{ marginRight: 20 }}>In Progress</span>) case 'ARCHIVED': return (<span className="tag is-small is-danger" style={{ marginRight: 20 }}>Archived</span>) default: return (<span></span>) } } export default StatusTag And back in our `BlogNav.js` let’s add the StatusTag next to the date. And don’t forget to import it. **import StatusTag from './../../components/StatusTag'** const BlogNav = ({ to, date, **status** }) => ( <nav className="level"> <div className="level-left"> <Link className="level-item button is-small is-link is-outlined" to={to}>Back to Blog</Link> </div> <div className="level-right"> **<StatusTag status={status} />** <p className="level-item has-text-link is-size-7"> {moment(date).calendar(null, { sameDay: '\[Today\]', lastDay: '\[Yesterday\]', lastWeek: '\[Last\] dddd', sameElse: 'MMM Do YYYY' })} </p> </div> </nav> ) And we need to update places we use the `<BlogNav … >` component. <BlogNav date={props.date} **status={props.status}** to="/blog" /> Now we have a nice little tag so we can let our readers know that we are still working on this article. ### Let’s Review * We learned about Contentful and signed up for an account * Created Contentful content * Connect Contentful to our app * Created a blog feed page * Created a blog feed items * Created a blog post page * Updated our Contentful content to realistic content * Set up React to render Markdown as Html * Refacted our code to make it cleaner * Added a blog Status tag Now, we have the basic blog that you can start using today if you wanted > **Next** — [Import your Medium Feed into React](https://medium.com/p/ceadbaf785c7/edit)