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;
**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;
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;
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;
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;
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
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
Top comments (0)