avatarMatteo Possamai

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

9791

Abstract

"hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Register<span class="hljs-tag"></<span class="hljs-name">h1</span>></span> <span class="hljs-tag"><<span class="hljs-name">AuthForm</span> <span class="hljs-attr">isRegister</span> /></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }; <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-title class_">Register</span>;</pre></div><h1 id="b23e">Step 4: Designing User Profiles and Posts</h1><p id="cb2e">Now, let’s create user profiles and the ability to create posts.</p><ol><li>In the <code>components</code> folder, create <code>Profile.js</code>:</li></ol><div id="a7fe"><pre><span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>; <span class="hljs-keyword">import</span> { auth, firestore } <span class="hljs-keyword">from</span> <span class="hljs-string">'../firebase'</span>;

<span class="hljs-keyword">const</span> <span class="hljs-title function_">Profile</span> = (<span class="hljs-params"></span>) => { <span class="hljs-keyword">const</span> [user, setUser] = <span class="hljs-title function_">useState</span>(<span class="hljs-literal">null</span>); <span class="hljs-title function_">useEffect</span>(<span class="hljs-function">() =></span> { <span class="hljs-keyword">const</span> unsubscribe = auth.<span class="hljs-title function_">onAuthStateChanged</span>(<span class="hljs-function">(<span class="hljs-params">authUser</span>) =></span> { <span class="hljs-keyword">if</span> (authUser) { firestore.<span class="hljs-title function_">collection</span>(<span class="hljs-string">'users'</span>).<span class="hljs-title function_">doc</span>(authUser.<span class="hljs-property">uid</span>).<span class="hljs-title function_">get</span>() .<span class="hljs-title function_">then</span>(<span class="hljs-function">(<span class="hljs-params">doc</span>) =></span> { <span class="hljs-keyword">if</span> (doc.<span class="hljs-property">exists</span>) { <span class="hljs-title function_">setUser</span>(doc.<span class="hljs-title function_">data</span>()); } }); } <span class="hljs-keyword">else</span> { <span class="hljs-title function_">setUser</span>(<span class="hljs-literal">null</span>); } }); <span class="hljs-keyword">return</span> <span class="hljs-function">() =></span> <span class="hljs-title function_">unsubscribe</span>(); }, []); <span class="hljs-keyword">return</span> ( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> {user ? ( <span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{user.photoURL}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{user.displayName}</span> /></span> <span class="hljs-tag"><<span class="hljs-name">h2</span>></span>{user.displayName}<span class="hljs-tag"></<span class="hljs-name">h2</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span> ) : ( <span class="hljs-tag"><<span class="hljs-name">p</span>></span>Please login to see your profile<span class="hljs-tag"></<span class="hljs-name">p</span>></span> )} <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }; <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-title class_">Profile</span>;</pre></div><ol><li>In the <code>pages</code> folder, create <code>profile.js</code>:</li></ol><div id="fb53"><pre><span class="hljs-keyword">import</span> <span class="hljs-title class_">Profile</span> <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/Profile'</span>;

<span class="hljs-keyword">const</span> <span class="hljs-title function_">ProfilePage</span> = (<span class="hljs-params"></span>) => { <span class="hljs-keyword">return</span> ( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Your Profile<span class="hljs-tag"></<span class="hljs-name">h1</span>></span> <span class="hljs-tag"><<span class="hljs-name">Profile</span> /></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }; <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-title class_">ProfilePage</span>;</pre></div><h1 id="f801">Step 5: Implementing Post Creation and Display</h1><p id="2e7c">Now, let’s allow users to create and display posts.</p><ol><li>In the <code>components</code> folder, create <code>PostForm.js</code>:</li></ol><div id="6e91"><pre><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>; <span class="hljs-keyword">import</span> { firestore, auth } <span class="hljs-keyword">from</span> <span class="hljs-string">'../firebase'</span>;

<span class="hljs-keyword">const</span> <span class="hljs-title function_">PostForm</span> = (<span class="hljs-params"></span>) => { <span class="hljs-keyword">const</span> [content, setContent] = <span class="hljs-title function_">useState</span>(<span class="hljs-string">''</span>); <span class="hljs-keyword">const</span> <span class="hljs-title function_">handleSubmit</span> = <span class="hljs-keyword">async</span> (<span class="hljs-params">e</span>) => { e.<span class="hljs-title function_">preventDefault</span>(); <span class="hljs-keyword">try</span> { <span class="hljs-keyword">if</span> (content) { <span class="hljs-keyword">await</span> firestore.<span class="hljs-title function_">collection</span>(<span class="hljs-string">'posts'</span>).<span class="hljs-title function_">add</span>({ content, <span class="hljs-attr">userId</span>: auth.<span class="hljs-property">currentUser</span>.<span class="hljs-property">uid</span>, <span class="hljs-attr">createdAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>(), }); <span class="hljs-title function_">setContent</span>(<span class="hljs-string">''</span>); } } <span class="hljs-keyword">catch</span> (error) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">'Error creating post:'</span>, error); } }; <span class="hljs-keyword">return</span> ( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>></span> <span class="hljs-tag"><<span class="hljs-name">textarea</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Write your post..."</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{content}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =></span> setContent(e.target.value)} /> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>></span>Post<span class="hljs-tag"></<span class="hljs-name">button</span>></span> <span class="hljs-tag"></<span class="hljs-name">form</span>></span></span> ); }; <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-title class_">PostForm</span>;</pre></div><ol><li>In the <code>components</code> folder, create <code>Post.js</code>:</li></ol><div id="7fc2"><pre><span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>; <span class="hljs-keyword">import</span> { firestore } <span class="hljs-keyword">from</span> <span class="hljs-string">'../firebase'</span>;

<span class="hljs-keyword">const</span> <span class="hljs-title function_">Post</span> = (<span class="hljs-params">{ postId, content, userId, createdAt }</span>) => { <span class="hljs-keyword">const</span> [user, setUser] = <span class="hljs-title function_">useState</span>(<span class="hljs-literal">null</span>); <span class="hljs-title function_">useEffect</span>(<span class="hljs-function">() =></span> { firestore.<span class="hljs-title function_">collection</span>(<span class="hljs-string">'users'</span>).<span class="hljs-title function_">doc</span>(userId).<span class="hljs-title function_">get</span>() .<span class="hljs-title function_">then</span>(<span class="hljs-function">(<span class="hljs-params">doc</span>) =></span> { <span class="hljs-keyword">if</span> (doc.<span class="hljs-property">exists</span>) { <span class="hljs-title function_">setUser</span>(doc.<span class="hljs-title function_">data</span>()); } }); }, [userId]); <span class="hljs-keyword">return</span> ( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> {user && ( <span class="hljs-tag"><<span class="hljs-name">div<

Options

/span>></span> <span class="hljs-tag"><<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{user.photoURL}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{user.displayName}</span> /></span> <span class="hljs-tag"><<span class="hljs-name">h3</span>></span>{user.displayName}<span class="hljs-tag"></<span class="hljs-name">h3</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span> )} <span class="hljs-tag"><<span class="hljs-name">p</span>></span>{content}<span class="hljs-tag"></<span class="hljs-name">p</span>></span> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>{createdAt.toDate().toLocaleString()}<span class="hljs-tag"></<span class="hljs-name">p</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }; <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-title class_">Post</span>;</pre></div><ol><li>In the <code>pages</code> folder, create <code>feed.js</code>:</li></ol><div id="f719"><pre><span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>; <span class="hljs-keyword">import</span> { firestore } <span class="hljs-keyword">from</span> <span class="hljs-string">'../firebase'</span>; <span class="hljs-keyword">import</span> <span class="hljs-title class_">PostForm</span> <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/PostForm'</span>; <span class="hljs-keyword">import</span> <span class="hljs-title class_">Post</span> <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/Post'</span>;

<span class="hljs-keyword">const</span> <span class="hljs-title function_">Feed</span> = (<span class="hljs-params"></span>) => { <span class="hljs-keyword">const</span> [posts, setPosts] = <span class="hljs-title function_">useState</span>([]); <span class="hljs-title function_">useEffect</span>(<span class="hljs-function">() =></span> { <span class="hljs-keyword">const</span> unsubscribe = firestore.<span class="hljs-title function_">collection</span>(<span class="hljs-string">'posts'</span>) .<span class="hljs-title function_">orderBy</span>(<span class="hljs-string">'createdAt'</span>, <span class="hljs-string">'desc'</span>) .<span class="hljs-title function_">onSnapshot</span>(<span class="hljs-function">(<span class="hljs-params">snapshot</span>) =></span> { <span class="hljs-title function_">setPosts</span>(snapshot.<span class="hljs-property">docs</span>.<span class="hljs-title function_">map</span>(<span class="hljs-function">(<span class="hljs-params">doc</span>) =></span> ({ <span class="hljs-attr">id</span>: doc.<span class="hljs-property">id</span>, ...doc.<span class="hljs-title function_">data</span>(), }))); }); <span class="hljs-keyword">return</span> <span class="hljs-function">() =></span> <span class="hljs-title function_">unsubscribe</span>(); }, []); <span class="hljs-keyword">return</span> ( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Feed<span class="hljs-tag"></<span class="hljs-name">h1</span>></span> <span class="hljs-tag"><<span class="hljs-name">PostForm</span> /></span> {posts.map((post) => ( <span class="hljs-tag"><<span class="hljs-name">Post</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{post.id}</span> {<span class="hljs-attr">...post</span>} /></span> ))} <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }; <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-title class_">Feed</span>;</pre></div><h1 id="480e">Step 6: Adding Real-Time Updates with WebSockets</h1><p id="2d8d">To enable real-time updates, we’ll integrate WebSockets using Firebase’s Firestore real-time listeners.</p><ol><li>In the <code>components</code> folder, update <code>Post.js</code>:</li></ol><div id="b246"><pre><span class="hljs-comment">// ... (previous code)</span>

<span class="hljs-keyword">import</span> { firestore } <span class="hljs-keyword">from</span> <span class="hljs-string">'../firebase'</span>; <span class="hljs-keyword">const</span> <span class="hljs-title function_">Post</span> = (<span class="hljs-params">{ postId, content, userId, createdAt }</span>) => { <span class="hljs-comment">// ... (previous code)</span> <span class="hljs-title function_">useEffect</span>(<span class="hljs-function">() =></span> { <span class="hljs-comment">// ... (previous code)</span> <span class="hljs-keyword">const</span> unsubscribe = firestore.<span class="hljs-title function_">collection</span>(<span class="hljs-string">'posts'</span>).<span class="hljs-title function_">doc</span>(postId) .<span class="hljs-title function_">onSnapshot</span>(<span class="hljs-function">(<span class="hljs-params">snapshot</span>) =></span> { <span class="hljs-keyword">if</span> (snapshot.<span class="hljs-property">exists</span>) { <span class="hljs-keyword">const</span> updatedPost = snapshot.<span class="hljs-title function_">data</span>(); <span class="hljs-title function_">setContent</span>(updatedPost.<span class="hljs-property">content</span>); } }); <span class="hljs-keyword">return</span> <span class="hljs-function">() =></span> <span class="hljs-title function_">unsubscribe</span>(); }, [postId]); <span class="hljs-keyword">return</span> ( <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> {/* ... (previous code) */} <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }; <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-title class_">Post</span>;</pre></div><h1 id="f6ae">Step 7: Styling with Tailwind CSS</h1><p id="b2e0">Finally, let’s enhance the visual appeal of our social network using Tailwind CSS.</p><ol><li>Open the <code>styles/globals.css</code> file and add the following:</li></ol><div id="f1a9"><pre><span class="hljs-keyword">@import</span> <span class="hljs-string">'tailwindcss/base'</span>; <span class="hljs-keyword">@import</span> <span class="hljs-string">'tailwindcss/components'</span>; <span class="hljs-keyword">@import</span> <span class="hljs-string">'tailwindcss/utilities'</span>;</pre></div><ol><li>Create a <code>tailwind.config.js</code> file in the project root and customize your styles:</li></ol><div id="91d2"><pre><span class="hljs-string">module.exports</span> <span class="hljs-string">=</span> { <span class="hljs-attr">purge:</span> [], <span class="hljs-attr">darkMode:</span> <span class="hljs-literal">false</span>, <span class="hljs-string">//</span> <span class="hljs-string">or</span> <span class="hljs-string">'media'</span> <span class="hljs-string">or</span> <span class="hljs-string">'class'</span> <span class="hljs-attr">theme:</span> { <span class="hljs-attr">extend:</span> {}, }, <span class="hljs-attr">variants:</span> { <span class="hljs-attr">extend:</span> {}, }, <span class="hljs-attr">plugins:</span> [], }<span class="hljs-string">;</span></pre></div><h1 id="a63e">Conclusion</h1><p id="9f07">Congratulations! You’ve successfully built a simple social network web app using Next.js. Through this hands-on project, you’ve gained insights into setting up authentication, real-time databases, user profiles, post creation, and real-time updates. By expanding on this foundation, you can add more features like user authentication, commenting, and user interactions to create a more robust social network platform. Remember, practical experience is key to mastering any technology, and this project is just the beginning of your coding journey.</p><p id="dfa0">The skills you’ve honed in this project — Next.js, Firebase, React, and Tailwind CSS — are valuable assets that can help you embark on even more ambitious web development projects. Whether you’re aiming to enhance your portfolio, learn new concepts, or prepare for job interviews, this simple social network web app serves as a testament to your dedication and growth as a programmer. Happy coding!</p><p id="0924">And there you have it — a step-by-step tutorial on how to build a simple social network web app using Next.js, Firebase, React, and Tailwind CSS. Remember, practice makes perfect, so don’t hesitate to modify and expand upon this project as you continue your web development journey.</p><h1 id="3d71">In Plain English</h1><p id="1be4"><i>Thank you for being a part of our community! Before you go:</i></p><ul><li><i>Be sure to <b>clap</b> and <b>follow</b> the writer! 👏</i></li><li><i>You can find even more content at <a href="https://plainenglish.io/"><b>PlainEnglish.io</b></a><b> 🚀</b></i></li><li><i>Sign up for our <a href="http://newsletter.plainenglish.io/"><b>free weekly newsletter</b></a>. 🗞️</i></li><li><i>Follow us on <a href="https://twitter.com/inPlainEngHQ"><b>Twitter</b></a></i>, <a href="https://www.linkedin.com/company/inplainenglish/"><b><i>LinkedIn</i></b></a>, <a href="https://www.youtube.com/channel/UCtipWUghju290NWcn8jhyAw"><b><i>YouTube</i></b></a>, and <a href="https://discord.gg/GtDtUAvyhW"><b><i>Discord</i></b></a><b><i>.</i></b></li></ul></article></body>

Building a Simple Social Network Web App with Next.js

A Hands-On Tutorial

Photo by Shoeib Abolhassani on Unsplash

In the exciting journey of mastering a new programming language, nothing beats the hands-on experience of building a real-world project. The practical application of concepts not only solidifies your understanding but also equips you with an impressive portfolio to showcase to potential employers. In this tutorial, we’ll embark on a journey to build a simple social network web app using Next.js — a powerful React framework. By the end of this tutorial, you’ll have a functional social network prototype, along with a deeper understanding of Next.js, React, and database integration.

Understanding the Project: A Simple Social Network

Before we dive into the code, let’s outline the project’s key features and components.

Key Features:

  1. User authentication and registration.
  2. User profiles with profile pictures and basic information.
  3. Creating, editing, and deleting posts.
  4. Liking and commenting on posts.
  5. Real-time updates using WebSockets.

Tech Stack:

  • Next.js: A React framework for server-side rendering and routing.
  • Firebase: A cloud-based platform for authentication and real-time database.
  • Tailwind CSS: A utility-first CSS framework for efficient styling.

Step 1: Setting Up Your Project

First, ensure you have Node.js and npm (Node Package Manager) installed on your machine. Open your terminal and create a new Next.js project:

npx create-next-app my-social-network

Navigate to the project directory:

cd my-social-network

Install the required dependencies:

npm install firebase tailwindcss

Step 2: Setting Up Firebase

Firebase will serve as our authentication and real-time database solution. Create a Firebase project and obtain your configuration settings from the Firebase console.

Authentication:

  1. Enable Email/Password authentication in the Firebase console.
  2. In the Next.js project, create a file named firebase.js in the root directory. Add your Firebase configuration:
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

const firebaseConfig = {
  apiKey: 'YOUR_API_KEY',
  authDomain: 'YOUR_AUTH_DOMAIN',
  projectId: 'YOUR_PROJECT_ID',
  storageBucket: 'YOUR_STORAGE_BUCKET',
  messagingSenderId: 'YOUR_MESSAGING_SENDER_ID',
  appId: 'YOUR_APP_ID',
};
if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig);
}
export const auth = firebase.auth();
export const firestore = firebase.firestore();

Real-time Database:

  1. Create a Firestore database in the Firebase console.
  2. Set up rules to secure your database (optional, but recommended).

Step 3: Building the User Authentication System

Authentication is the cornerstone of any social network. Let’s create a user registration and login system.

  1. Create a components folder in the project directory. Inside, create AuthForm.js:
import { useState } from 'react';
import { auth } from '../firebase';

const AuthForm = ({ isRegister }) => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      if (isRegister) {
        await auth.createUserWithEmailAndPassword(email, password);
      } else {
        await auth.signInWithEmailAndPassword(email, password);
      }
    } catch (error) {
      console.error('Authentication Error:', error);
    }
  };
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        placeholder="Email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <input
        type="password"
        placeholder="Password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button type="submit">{isRegister ? 'Register' : 'Login'}</button>
    </form>
  );
};
export default AuthForm;
  1. In the pages folder, create login.js and register.js:
import AuthForm from '../components/AuthForm';

const Login = () => {
  return (
    <div>
      <h1>Login</h1>
      <AuthForm />
    </div>
  );
};
export default Login;
import AuthForm from '../components/AuthForm';

const Register = () => {
  return (
    <div>
      <h1>Register</h1>
      <AuthForm isRegister />
    </div>
  );
};
export default Register;

Step 4: Designing User Profiles and Posts

Now, let’s create user profiles and the ability to create posts.

  1. In the components folder, create Profile.js:
import { useState, useEffect } from 'react';
import { auth, firestore } from '../firebase';

const Profile = () => {
  const [user, setUser] = useState(null);
  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((authUser) => {
      if (authUser) {
        firestore.collection('users').doc(authUser.uid).get()
          .then((doc) => {
            if (doc.exists) {
              setUser(doc.data());
            }
          });
      } else {
        setUser(null);
      }
    });
    return () => unsubscribe();
  }, []);
  return (
    <div>
      {user ? (
        <div>
          <img src={user.photoURL} alt={user.displayName} />
          <h2>{user.displayName}</h2>
        </div>
      ) : (
        <p>Please login to see your profile</p>
      )}
    </div>
  );
};
export default Profile;
  1. In the pages folder, create profile.js:
import Profile from '../components/Profile';

const ProfilePage = () => {
  return (
    <div>
      <h1>Your Profile</h1>
      <Profile />
    </div>
  );
};
export default ProfilePage;

Step 5: Implementing Post Creation and Display

Now, let’s allow users to create and display posts.

  1. In the components folder, create PostForm.js:
import { useState } from 'react';
import { firestore, auth } from '../firebase';

const PostForm = () => {
  const [content, setContent] = useState('');
  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      if (content) {
        await firestore.collection('posts').add({
          content,
          userId: auth.currentUser.uid,
          createdAt: new Date(),
        });
        setContent('');
      }
    } catch (error) {
      console.error('Error creating post:', error);
    }
  };
  return (
    <form onSubmit={handleSubmit}>
      <textarea
        placeholder="Write your post..."
        value={content}
        onChange={(e) => setContent(e.target.value)}
      />
      <button type="submit">Post</button>
    </form>
  );
};
export default PostForm;
  1. In the components folder, create Post.js:
import { useState, useEffect } from 'react';
import { firestore } from '../firebase';

const Post = ({ postId, content, userId, createdAt }) => {
  const [user, setUser] = useState(null);
  useEffect(() => {
    firestore.collection('users').doc(userId).get()
      .then((doc) => {
        if (doc.exists) {
          setUser(doc.data());
        }
      });
  }, [userId]);
  return (
    <div>
      {user && (
        <div>
          <img src={user.photoURL} alt={user.displayName} />
          <h3>{user.displayName}</h3>
        </div>
      )}
      <p>{content}</p>
      <p>{createdAt.toDate().toLocaleString()}</p>
    </div>
  );
};
export default Post;
  1. In the pages folder, create feed.js:
import { useState, useEffect } from 'react';
import { firestore } from '../firebase';
import PostForm from '../components/PostForm';
import Post from '../components/Post';

const Feed = () => {
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    const unsubscribe = firestore.collection('posts')
      .orderBy('createdAt', 'desc')
      .onSnapshot((snapshot) => {
        setPosts(snapshot.docs.map((doc) => ({
          id: doc.id,
          ...doc.data(),
        })));
      });
    return () => unsubscribe();
  }, []);
  return (
    <div>
      <h1>Feed</h1>
      <PostForm />
      {posts.map((post) => (
        <Post key={post.id} {...post} />
      ))}
    </div>
  );
};
export default Feed;

Step 6: Adding Real-Time Updates with WebSockets

To enable real-time updates, we’ll integrate WebSockets using Firebase’s Firestore real-time listeners.

  1. In the components folder, update Post.js:
// ... (previous code)

import { firestore } from '../firebase';
const Post = ({ postId, content, userId, createdAt }) => {
  // ... (previous code)
  useEffect(() => {
    // ... (previous code)
    const unsubscribe = firestore.collection('posts').doc(postId)
      .onSnapshot((snapshot) => {
        if (snapshot.exists) {
          const updatedPost = snapshot.data();
          setContent(updatedPost.content);
        }
      });
    return () => unsubscribe();
  }, [postId]);
  return (
    <div>
      {/* ... (previous code) */}
    </div>
  );
};
export default Post;

Step 7: Styling with Tailwind CSS

Finally, let’s enhance the visual appeal of our social network using Tailwind CSS.

  1. Open the styles/globals.css file and add the following:
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
  1. Create a tailwind.config.js file in the project root and customize your styles:
module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
};

Conclusion

Congratulations! You’ve successfully built a simple social network web app using Next.js. Through this hands-on project, you’ve gained insights into setting up authentication, real-time databases, user profiles, post creation, and real-time updates. By expanding on this foundation, you can add more features like user authentication, commenting, and user interactions to create a more robust social network platform. Remember, practical experience is key to mastering any technology, and this project is just the beginning of your coding journey.

The skills you’ve honed in this project — Next.js, Firebase, React, and Tailwind CSS — are valuable assets that can help you embark on even more ambitious web development projects. Whether you’re aiming to enhance your portfolio, learn new concepts, or prepare for job interviews, this simple social network web app serves as a testament to your dedication and growth as a programmer. Happy coding!

And there you have it — a step-by-step tutorial on how to build a simple social network web app using Next.js, Firebase, React, and Tailwind CSS. Remember, practice makes perfect, so don’t hesitate to modify and expand upon this project as you continue your web development journey.

In Plain English

Thank you for being a part of our community! Before you go:

Nextjs
JavaScript
Javascript Tips
Programming
Software Development
Recommended from ReadMedium