How to create a blog website with React & firebase -> Series2
Tags: javascript, react, webdev, firebase
Published: 2022-06-19 08:12:08

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](https://dev.to/evansifyke/how-to-create-a-blog-website-with-react-firebase-series-34pk) or [Here too](https://melbite.com/melbite/ds8h6KBDZUY0C2FXkKLt)

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.
``` javascript
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;
```
**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.
``` javascript
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;
```
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.

``` javascript 
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;
```
**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 
``` javascript
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;
```
**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.

``` javascript 
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;
```
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
``` javascript 
npm install react-router-dom
```
### 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](https://melbite.com/melbite/bwQhVVabIuIkphbqqFkD)

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

To get the source code of this beautiful application [check my github](https://github.com/Evans-mutuku/auth-upload.git)