DEV Community

Cover image for How to create a blog website with React & firebase -> Series2
Melbite blogging Platform
Melbite blogging Platform

Posted on • Originally published at melbite.com

How to create a blog website with React & firebase -> Series2

Hello dev community,

Welcome to this series where we are building blogging website with react and firebase.

In the last tutorial we prepared the environments and created the login and HomePage
Check it out here or Here too

In this article we are going to complete out build. Let's prepare the UI where the user will add an image and caption of the image.

Create CreatePost.js file that will contain the following codes.

import React, { useState } from "react";
import { useSelector } from "react-redux";
import { selectUser } from "../features/userSlice";
import { db } from "../utils/firebase";
import firebase from "firebase/compat/app";

const CreatePost = () => {
  const user = useSelector(selectUser);

  const [postTitle, setPostTitle] = useState("");
  const [imageURL, setimageURL] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();

    db.collection("posts").add({
      uid: user.uid,
      message: postTitle,
      displayName: user?.displayName,
      image: imageURL,
      timestamp: firebase.firestore.FieldValue.serverTimestamp(),
    });

    setPostTitle("");
    setimageURL("");
  };
  return (
    <div className="w-full mx-auto py-3 px-3 border bg-white  border-gray-300 rounded-md">
      <form className="mx-auto">
        <input
          value={postTitle}
          onChange={(e) => setPostTitle(e.target.value)}
          className="rounded-full w-full border outline-2 px-5 py-2 focus:outline-green-600"
          type="text"
          placeholder="Enter Post Caption"
        />
        <input
          value={imageURL}
          onChange={(e) => setimageURL(e.target.value)}
          className="rounded-full mt-6 w-full border outline-2 px-5 py-2 focus:outline-green-600"
          type="text"
          placeholder="Enter Image Url"
        />
        <button onClick={handleSubmit} className="hidden" type="submit">
          Hidden Submit
        </button>
      </form>
    </div>
  );
};

export default CreatePost;
Enter fullscreen mode Exit fullscreen mode

**Note: **Our image input is a string meaning that we will paste image url from the internet or any other source.

Enter values from the input field and press Enter Key and your data will be submitted to the firestore database.

When we check at our firebase firestore we shall find that a new collection called posts has been created.

Now we need to fetch that data from the db to our webpage.

To fetch our data we will make use of useEffect() hook. Let's create feed.js file that will help us fetch and hold our data.

import React, { useState, useEffect } from "react";
import { db } from "../utils/firebase";
import Post from "./Post";

function Feed() {
  // fetch posts and store them in an array
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    db.collection("posts")
      .orderBy("timestamp", "desc")
      .onSnapshot((snapshot) =>
        setPosts(snapshot.docs.map((doc) => ({ id: doc.id, data: doc.data() })))
      );
  }, []);
  return (
    <div className="feed">
      {posts.map((post) => (
        <Post
          key={post.id}
          message={post.data.message}
          timestamp={post.data.timestamp}
          displayName={post.data.displayName}
          image={post.data.image}
          likes={post.data.likes}
          uid={post.data.uid}
        />
      ))}
    </div>
  );
}

export default Feed;
Enter fullscreen mode Exit fullscreen mode

Note: we have used the map() function instead of forEach() ** function to map all the posts from our firestore collection, this is because **map() is the new thing in town 😊.

Now we have fetched our data from firestore, let's create post.js file that will handle the post details and display on the web page.

import React from "react";

function Post({ displayName, image, timestamp, message }) {
  return (
    <div className="bg-white border border-gray-300 py-3 px-3 mt-3 mb-3 rounded-md">
      <div className="flex items-center justify-between border-b-2 pb-2">
        <div className="flex items-center space-x-3 ">
          <div className="text-center items-center pt-3  bg-green-600 text-white rounded-full w-12 h-12">
            {displayName[0]}
          </div>
          <div className="">
            <h3>{displayName}</h3>
            <p className="text-xs text-gray-500">
              {new Date(timestamp?.toDate()).toUTCString()}
            </p>
          </div>
        </div>
      </div>

      <div className="mt-3">
        <p>{message}</p>
      </div>

      <div className="mt-5">
        <img className="w-full h-56 " src={image} alt="" />
      </div>

      <div className=" mt-3 flex justify-between items-center w-full">
        <div className="cursor-pointer bg-gray-100 hover:bg-gray-200 text-green-600 py-1 px-2">
          <p>Like</p>
        </div>
        <div className="cursor-pointer bg-gray-100 hover:bg-gray-200 text-green-600 py-1 px-2">
          <p>Comment</p>
        </div>
        <div className="cursor-pointer bg-gray-100 hover:bg-gray-200 text-green-600 py-1 px-2">
          <p>Share</p>
        </div>
      </div>
    </div>
  );
}

export default Post;
Enter fullscreen mode Exit fullscreen mode

Note: we are importing all the props from feed.js file.

Now we are done from sending out post and fetching it from firestore. Let's export our feed.js file to our HomePage.js file

import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { login, logout, selectUser } from "../features/userSlice";
import { auth } from "../utils/firebase";
import CreatePost from "./CreatePost";
import Feed from "./Feed";
import Header from "./Header";

const HomePage = () => {
  const user = useSelector(selectUser);
  const dispatch = useDispatch();

  useEffect(() => {
    auth.onAuthStateChanged((userAuth) => {
      if (userAuth) {
        dispatch(
          login({
            email: userAuth.email,
            uid: userAuth.uid,
            displayName: userAuth.displayName,
          })
        );
      } else {
        dispatch(logout);
      }
    });
  }, [dispatch]);
  return (
    <>
      <Header />
      <div className="flex space-x-10 justify-between w-5/6 mx-auto mt-5">
        <div className="hidden h-40 bg-white rounded-md border border-1 border-gray-300 pb-5 md:flex flex-col items-center w-2/6 ">
          <img
            className=" rounded-t-md h-20 w-full"
            src="https://images.unsplash.com/photo-1542831371-29b0f74f9713?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8M3x8Y29kaW5nfGVufDB8fDB8fA%3D%3D&w=1000&q=80"
            alt="text"
          />
          <div className="text-center items-center pt-3 -mt-7 bg-green-600 text-white rounded-full w-12 h-12">
            {user?.displayName[0]}
          </div>
          <p className="mt-3">{user.displayName}</p>
        </div>
        <div className="mx-auto w-full">
          <CreatePost />
          <Feed />
        </div>
        <div className="hidden bg-white rounded-md border border-1 border-gray-300 pb-5 md:block py-4 px-2 w-2/6 h-80">
          <h2>Trending topics</h2>
          <div className="text-left items-center pt-3 space-y-5">
            <p className="text-sm text-gray-600">#Javascript</p>
            <p className="text-sm text-gray-600">#Java</p>
            <p className="text-sm text-gray-600">#Typescript</p>
            <p className="text-sm text-gray-600">#Python</p>
            <p className="text-sm text-gray-600">#Data Science</p>
            <p className="text-sm text-gray-600">#Machine Learning</p>
          </div>
        </div>
      </div>
    </>
  );
};

export default HomePage;
Enter fullscreen mode Exit fullscreen mode

Note: we are using the home page to style our application so we can export our page to the App.js file and handle the authentication to show the homepage if the user is not logged-in.

Now let's import our HomePage.js file to our App.js file.

import React, { useEffect } from "react";
import { Routes, Route } from "react-router-dom";
import HomePage from "./components/HomePage";
import "./App.css";
import Login from "./components/Login";
import { useDispatch, useSelector } from "react-redux";
import { login, logout, selectUser } from "./features/userSlice";
import { auth } from "./utils/firebase";

function App() {
  const dispatch = useDispatch();
  const user = useSelector(selectUser);

  //validate and keep the user loggedIn
  useEffect(() => {
    auth.onAuthStateChanged((userAuth) => {
      if (userAuth) {
        dispatch(
          login({
            email: userAuth.email,
            uid: userAuth.uid,
            displayName: userAuth.displayName,
            profilePic: userAuth.photoURL,
          })
        );
      } else {
        dispatch(logout);
      }
    });
  }, [dispatch]);
  return (
    <div className="">
      <Routes>
        {!user ? (
          <Route path="/" element={<Login />} />
        ) : (
          <Route path="/" element={<HomePage />} />
        )}
      </Routes>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

In App.js file we have made use of react-router-dom to handle our routes when the user is authenticated.
To install react-router-dom use the following command

npm install react-router-dom
Enter fullscreen mode Exit fullscreen mode

Conclusion

We have finally created a complete blogging website with react and firebase. In our final build on this series, we are going to deploy it to firebase.

This article series was originally published at melbite.com/create-blogging-web-with-react-firebase

You can find more of my articles on https://melbite.com

To get the source code of this beautiful application check my github

Discussion (0)