Gatsby Default Starter

Post Component in React

Written on August 01, 2019

This is the sixth part of Create react app with GraphQL way of WordPress data

In this part, we will develop a Post component for our application. But, before diving in this, we will develop a Loading component for seeing landing or search status in our application. Let’s dive into Loading component development.

Create a file named styled.js in the components directory. In this file first import styled and keyframes class from the styled-components package. Styled class is familiar to us. It helps us to style a component efficient way. Beside, the keyframes helper class will help us to develop animation. Keyframes in this package work as CSS3 @keyframes rule.

import styled, { keyframes } from "styled-components";

Then, assign styled in an exported constant named LoadingState. In this constant first, declare some general properties and in after pseudo-element define animation-name loading in special way. So, create a constant variable named loading. In this variable, we use keyframes and define animation as usual. Finally, styled.js is looked like this

import styled, { keyframes } from "styled-components";

const loading = keyframes`
    from {
      transform: scale(1);
    }
    to {
      transform: scale(1.5);
    }
`;

const LoadingState = styled.div`
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  &:after {
    content: "";
    position: absolute;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background-color: #dedede;
    opacity: 0.4;
    animation: ${loading} 1s linear 0.1s infinite alternate;
  }
`;

export default LoadingState;

Now, we can import LoadingState both in App.js and Post.js. Awesome way to reuse.
Open src/components/App.js and delete styled-component import lines and related code. Just import LoadingState from styled.js file and use it second return in the render method. Now, src/components/App.js looks like this-

import React from "react";
import styled from "styled-components";
import Posts from "./Posts";
import PostWidget from "./PostWidget";
import LoadingState from "./styled";

const Widget = styled.div`
  border: 1px solid gray;
  padding: 10px;
  p {
    margin-bottom: 0;
    border-top: 1px solid gray;
    }
  }
`;

class App extends React.Component {
  render() {
    if (this.props.state.length) {
      return (
        <div className="row">
          <div className="column column-80">
            {this.props.state.map(post => (
              <Posts key={post.node.id} post={post} />
            ))}
          </div>
          <div className="column column-20">
            <Widget>
              <h3>Recent posts</h3>
              {this.props.state.slice(0, 2).map(post => (
                <PostWidget key={post.node.id} post={post} />
              ))}
            </Widget>
          </div>
        </div>
      );
    }
    return <LoadingState>Loading...</LoadingState>;
  }
}
export default App;

Let’s dive into Post component development.

Post component development

Open src/components/post.js. First import React from react package, Dompurify from dompurify package and LoadingState from styled.js which we developed just.

import React from "react";
import DOMPurify from "dompurify";
import LoadingState from "./styled";

Then, in our Post’s render method, we have to write a little bit complex (for me) code block.

  • The check component has stated in its props.
  • During the checking time render LoadingState component.
  • Get post ID from props match object.
  • Loop every state and check this node id is equal to post id.
  • If found, store this state object in a predefined variable postInfo.
  • If not found, just render Post Not Found
  • When post found, return post title, body in a defined format.

In code, this algorithm will be,

if (this.props.state.length) {
      let postInfo = {};
      const state = this.props.state;
      const postID = this.props.match.params.postID;
      state.forEach(function(post, index) {
        if (post.node.id === postID) {
          postInfo = post;
        }
      });
      if (postInfo.node) {
        return (
          <div className="column">
            <h2
              dangerouslySetInnerHTML={{
                __html: DOMPurify.sanitize(postInfo.node.title)
              }}
            />
            <p
              dangerouslySetInnerHTML={{
                __html: DOMPurify.sanitize(postInfo.node.content)
              }}
            />
          </div>
        );
      } else {
        return <div>Post Not Found</div>;
      }
    }
    return <LoadingState>Searching...</LoadingState>;

So, the final code of src/component/post.js

import React from "react";
import DOMPurify from "dompurify";
import LoadingState from "./styled";

class Post extends React.Component {
  render() {
    if (this.props.state.length) {
      let postInfo = {};
      const state = this.props.state;
      const postID = this.props.match.params.postID;
      state.forEach(function(post, index) {
        if (post.node.id === postID) {
          postInfo = post;
        }
      });
      if (postInfo.node) {
        return (
          <div className="column">
            <h2
              dangerouslySetInnerHTML={{
                __html: DOMPurify.sanitize(postInfo.node.title)
              }}
            />
            <p
              dangerouslySetInnerHTML={{
                __html: DOMPurify.sanitize(postInfo.node.content)
              }}
            />
          </div>
        );
      } else {
        return <div>Post Not Found</div>;
      }
    }
    return <LoadingState>Searching...</LoadingState>;
  }
}
export default Post;