React & firebase로 블로그 웹사이트 만드는 방법 -> Series2

안녕하세요 개발자 커뮤니티입니다.

react 및 firebase로 블로그 웹사이트를 구축하는 이 시리즈에 오신 것을 환영합니다.

마지막 튜토리얼에서 환경을 준비하고 loginHomePage를 생성했습니다.
확인하거나 Here too

이 기사에서는 빌드를 완료할 것입니다. 사용자가 이미지와 이미지의 캡션을 추가할 UI를 준비합시다.

다음 코드를 포함할 CreatePost.js 파일을 생성합니다.

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;


**참고: **우리의 이미지 입력은 인터넷이나 다른 소스에서 이미지 URL을 붙여넣을 것임을 의미하는 문자열입니다.

입력 필드에서 값을 입력하고 Enter 키를 누르면 데이터가 firestore 데이터베이스에 제출됩니다.

firebase firestore에서 확인하면 posts라는 새 컬렉션이 생성되었음을 알 수 있습니다.

이제 db에서 웹 페이지로 해당 데이터를 가져와야 합니다.

데이터를 가져오기 위해 useEffect() 후크를 사용합니다. 데이터를 가져오고 보관하는 데 도움이 되는 파일feed.js을 생성해 보겠습니다.

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;


참고: firestore 컬렉션의 모든 게시물을 매핑하기 위해 forEach() ** 함수 대신 map() 함수를 사용했습니다. 이는 **map()이 새로운 기능이기 때문입니다 😊.

이제 Firestore에서 데이터를 가져왔으므로 게시물 세부 정보를 처리하고 웹 페이지에 표시할 파일post.js을 생성해 보겠습니다.

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;


참고: feed.js 파일에서 모든 소품을 가져오고 있습니다.

이제 게시물을 보내고 Firestore에서 가져오는 작업이 완료되었습니다. feed.js 파일을 HomePage.js 파일로 내보내겠습니다.

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;


참고: 우리는 홈페이지를 사용하여 응용 프로그램의 스타일을 지정하므로 페이지를 App.js 파일로 내보내고 사용자가 로그인하지 않은 경우 홈페이지를 표시하도록 인증을 처리할 수 있습니다.

이제 HomePage.js 파일을 App.js 파일로 가져오겠습니다.

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;


App.js 파일에서 사용자가 인증될 때 경로를 처리하기 위해 react-router-dom를 사용했습니다.
react-router-dom을 설치하려면 다음 명령을 사용하십시오.

npm install react-router-dom


결론



우리는 마침내 react와 firebase로 완벽한 블로그 웹사이트를 만들었습니다. 이 시리즈의 최종 빌드에서는 Firebase에 배포할 것입니다.

이 기사 시리즈는 원래 melbite.com/create-blogging-web-with-react-firebase에 게시되었습니다.

https://melbite.com에서 내 기사를 더 찾을 수 있습니다.

이 아름다운 애플리케이션의 소스 코드를 얻으려면check my github

좋은 웹페이지 즐겨찾기