ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React] ์‹ค์Šต - react twittler SPA
    codeStates front-end/React 2023. 1. 25. 20:25
    ๋ฐ˜์‘ํ˜•

     

     

     

     

    ๐Ÿ“Œ react twittler SPA

     

     

     

    ๐Ÿ“– ํ•™์Šต ๋ชฉํ‘œ

     

    React Router ์„ค์น˜

    • react-router-dom ์„ npm์œผ๋กœ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ์ƒ์„ธ ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„ํ•˜๊ธฐ

    • App ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ(App.js)
      • import ๋ฅผ ์ด์šฉํ•˜์—ฌ Tweets, MyPage, About ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค.
    • Sidebar ๋ฉ”๋‰ด ์ปดํฌ๋„ŒํŠธ(Sidebar.js)
      • Font Awesome์„ ํ™œ์šฉํ•˜์—ฌ About ์•„์ด์ฝ˜ <i className="far fa-question-circle"></i>์„ ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
      • Font Awesome์„ ํ™œ์šฉํ•˜์—ฌ MyPage ์•„์ด์ฝ˜ <i className="far fa-user"></i>์„ ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • Tweets ์ปดํฌ๋„ŒํŠธ(Tweets.js)
      • import ๋ฅผ ์ด์šฉํ•˜์—ฌ Footer ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
      • dummyTweets์˜ ๊ธธ์ด๋งŒํผ ํŠธ์œ—์ด ๋ณด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค
    • MyPage ์ปดํฌ๋„ŒํŠธ(MyPage.js)
      • import ๋ฅผ ์ด์šฉํ•˜์—ฌ Footer ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
      • kimcoding์ด ์ž‘์„ฑํ•œ ํŠธ์œ—๋งŒ ๋ณด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    React Route ์ ์šฉํ•˜๊ธฐ

    • ๊ฐ ๋ฉ”๋‰ด๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ, ์ฃผ์†Œ์— ๋งž๊ฒŒ ํŽ˜์ด์ง€ ๋ทฐ๊ฐ€ ๊ตฌํ˜„๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ์ปดํฌ๋„ŒํŠธ๋ณ„ ๊ธฐ์ˆ  ์š”๊ตฌ์‚ฌํ•ญ

    • App ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ(App.js)
      • <BrowserRouter>, <Routes>, <Route> ๋กœ React Router ๋ฌธ๋ฒ•์— ๋งž๊ฒŒ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
      • ์ฃผ์†Œ์— ๋”ฐ๋ฅธ ํŽ˜์ด์ง€๋ฅผ <Route> ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตฌ๋ถ„ ์ง€์–ด ์ค๋‹ˆ๋‹ค.
        • Tweets์ปดํฌ๋„ŒํŠธ์˜ Route path๋Š” "/"์ž…๋‹ˆ๋‹ค.
        • About ์ปดํฌ๋„ŒํŠธ์˜ Route path๋Š” "/about"์ž…๋‹ˆ๋‹ค.
        • MyPage ์ปดํฌ๋„ŒํŠธ์˜ Route path๋Š” "/mypage"์ž…๋‹ˆ๋‹ค.
    • Sidebar ๋ฉ”๋‰ด ์ปดํฌ๋„ŒํŠธ(Sidebar.js)
      • <Link> ์ปดํฌ๋„ŒํŠธ์˜ to ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ SPA ๋‚ด์—์„œ ํŽ˜์ด์ง€ ์ „ํ™˜์— ๋”ฐ๋ฅธ URL ์—…๋ฐ์ดํŠธ๋ฅผ ์ง„ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
        • Tweets ์ปดํฌ๋„ŒํŠธ์˜ Route path๋Š” "/"์ž…๋‹ˆ๋‹ค.
        • About ์ปดํฌ๋„ŒํŠธ์˜ Route path๋Š” "/about"์ž…๋‹ˆ๋‹ค.
        • MyPage ์ปดํฌ๋„ŒํŠธ์˜ Route path๋Š” "/mypage"์ž…๋‹ˆ๋‹ค.

     

     

    ๋ณธ ์‹ค์Šต์€ ์ฝ”๋“œ์Šคํ…Œ์ด์ธ ์—์„œ ์ˆ˜ํ–‰ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

     

     

    ์ฝ”๋”ฉ๋ถ€ํŠธ์บ ํ”„ | ์ฝ”๋“œ์Šคํ…Œ์ด์ธ  - ๋น„์ „๊ณต์ƒ๋„ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

    ์ฝ”๋”ฉ๋ถ€ํŠธ์บ ํ”„๋ฅผ ์ฐพ๋Š”๋‹ค๋ฉด? ๊ฐœ๋ฐœ์ž๋กœ ์ปค๋ฆฌ์–ด ์ „ํ™˜์„ ์œ„ํ•œ ์ฑ…์ž„์žˆ๋Š” ์ฝ”๋”ฉ ๊ต์œก ๊ธฐ๊ด€! ์„œ๋น„์Šค ๊ธฐํš์ž, ๊ทธ๋กœ์Šค ๋งˆ์ผ€ํ„ฐ, ๋ฐ์ดํ„ฐ ์‚ฌ์ด์–ธํ‹ฐ์ŠคํŠธ ๋“ฑ ๋‹ค์–‘ํ•œ ์ „๋ฌธ ์ปค๋ฆฌ์–ด์— ๋„์ „ํ•˜์„ธ์š”. ์ทจ์—… ์„ฑ๊ณต์˜ ํ›„๊ธฐ

    www.codestates.com

     

     

     

    ๋ณธ ์‹ค์Šต์„ ์œ„ํ•ด ๊ฑด๋“ค์ธ ์ฝ”๋“œ๋Š” ๋นจ๊ฐ„ ๋ฐ•์Šค ์ž…๋‹ˆ๋‹ค.

     

     

     

    App.js

     

    import React from 'react';
    import './App.css';
    import './global-style.css';
    // TODO - react-router-dom์„ ์„ค์น˜ ํ›„, import ๊ตฌ๋ฌธ์„ ์ด์šฉํ•˜์—ฌ BrowserRouter, Routes, Route ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์„ธ์š”.
    import { BrowserRouter, Routes, Route } from 'react-router-dom';
    import Sidebar from './Sidebar';
    import Tweets from './Pages/Tweets';
    // TODO - import๋ฌธ์„ ์ด์šฉํ•˜์—ฌ MyPage, About ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์„ธ์š”.
    import About from './Pages/About';
    import MyPage from './Pages/MyPage';
    
    
    const App = () => {
      return (
        <div>
          {/* TODO - BrowserRouter ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. */}
          <BrowserRouter>
          <div className="App">
            <main>
              <Sidebar />
              <section className="features">
                {/* TODO - Routes์™€ Route ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฒฝ๋กœ(path)๋ฅผ ์„ค์ •ํ•˜๊ณ  Tweets, Mypage, About ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. */}
                <Routes>
                <Route path="/" element={<Tweets />} /> 
                <Route path="/mypage" element={<MyPage />} /> 
                <Route path="/about" element={<About />} /> 
                </Routes>
              </section>
            </main>
          </div>
          </BrowserRouter>
        </div>
    
      );
    };
    
    // ! ์•„๋ž˜ ์ฝ”๋“œ๋Š” ์ˆ˜์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    export default App;

     

    Sidebar.js

     

    import React from 'react';
    // TODO - import๋ฌธ์„ ์ด์šฉํ•˜์—ฌ react-router-dom ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ Link ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค.
    import {Link} from "react-router-dom";
    
    const Sidebar = () => {
      return (
        <section className="sidebar">
          {/* TODO : About ๋ฉ”๋‰ด ์•„์ด์ฝ˜๊ณผ Mypage ๋ฉ”๋‰ด ์•„์ด์ฝ˜์„ ์ž‘์„ฑํ•˜๊ณ  Link ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฒฝ๋กœ(path)๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. */}
          <Link to="/">
            <i className="far fa-comment-dots"></i> // className์€ npm test์˜ ์˜ํ•ด ์ •์˜
            </Link>
            <Link to="/about">
            <i className="far fa-question-circle"></i>
            </Link>
            <Link to="/mypage">
            <i className="far fa-user"></i>
            </Link>
        </section>
      );
    };
    
    export default Sidebar;

     

    Tweet.js

     

    import React from 'react';
    import { dummyTweets } from '../static/dummyData';
    import './Tweets.css';
    // ! ์œ„ ์ฝ”๋“œ๋Š” ์ˆ˜์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    
    // TODO - import๋ฌธ์„ ์ด์šฉํ•˜์—ฌ Footer ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์„ธ์š”.
    import Footer from '../Footer';
    
    const Tweets = () => {
      return (
        <div>
          <div className="tweetForm__container">
            <div className="tweetForm__wrapper">
              <div className="tweetForm__input">
                <div className="tweetForm__inputWrapper">
                  <div className="tweetForm__count" role="status">
                    <span className="tweetForm__count__text">
                      {'total: ' + dummyTweets.length}
                    </span>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <ul className="tweets">
            {dummyTweets.map((tweet) => {
              return (
              <li className="tweet" key={tweet.id}>
                <div className="tweet__profile">
                  <img src={tweet.picture} />
                </div>
                <div className="tweet__content">
                  <div className="tweet__userInfo">
                    <span className="tweet__username">{tweet.username}</span>
                    <span className="tweet__createdAt">{tweet.createdAt}</span>
                  </div>
                  <div className="tweet__message">{tweet.content}</div>
                </div>
              </li>
              )
            })}
          </ul>
          {/* TODO - Footer ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. */}
          <Footer />
        </div>
      );
    };
    
    
    export default Tweets;

     

    MyPage.js

     

    import React from "react";
    import { dummyTweets } from "../static/dummyData";
    import "./MyPage.css";
    // ! ์œ„ ์ฝ”๋“œ๋Š” ์ˆ˜์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    
    // TODO - import๋ฌธ์„ ์ด์šฉํ•˜์—ฌ Footer ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค.
    import Footer from "../Footer";
    
    const MyPage = () => {
      // TODO - filter ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ username์ด kimcoding์ธ ์š”์†Œ๋งŒ ์žˆ๋Š” ๋ฐฐ์—ด์„ filteredTweet์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.
      const filteredTweets = dummyTweets.filter( (tweet) =>
        tweet.username === "kimcoding"); // ๊ณ ์ฐจํ•จ์ˆ˜ filter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •์˜
    
      return (
        <section className="myInfo">
          <div className="myInfo__container">
            <div className="myInfo__wrapper">
              <div className="myInfo__profile">
                <img src={filteredTweets[0].picture} />
              </div>
              <div className="myInfo__detail">
                <p className="myInfo__detailName">
                  {filteredTweets[0].username} Profile
                </p>
                <p>28 ํŒ”๋กœ์›Œ 100 ํŒ”๋กœ์ž‰</p>
              </div>
            </div>
          </div>
          <ul className="tweets__mypage">
            {/* TODO : dummyTweets์ค‘ kimcoding ์ด ์ž‘์„ฑํ•œ ํŠธ์œ— ๋ฉ”์„ธ์ง€๋งŒ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. */}
            {filteredTweets.map((tweet) => { // ์œ„์˜ ์ •์˜๋œ filteredTweets๋ฅผ map ํ•จ์ˆ˜๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๋ณด์—ฌ์ค€๋‹ค
            return (
              <li className="tweet" id={tweet.id} key={tweet.id}> // ์ •์˜๋œ fliterํ•จ์ˆ˜์˜ ๊ฐ’์„ ๋„ฃ๋Š”๋‹ค
              <div className="tweet__profile">
                <img src={tweet.profile} /> // ์ •์˜๋œ fliterํ•จ์ˆ˜์˜ ๊ฐ’์„ ๋„ฃ๋Š”๋‹ค
              </div>
              <div className="tweet__content">
                <div className="tweet__userInfo">
                  <span className="tweet__username">{tweet.username}</span> // ์ •์˜๋œ fliterํ•จ์ˆ˜์˜ ๊ฐ’์„ ๋„ฃ๋Š”๋‹ค
                  <span className="tweet__createdAt">{tweet.createdAt}</span> // ์ •์˜๋œ fliterํ•จ์ˆ˜์˜ ๊ฐ’์„ ๋„ฃ๋Š”๋‹ค
                </div>
                <div className="tweet__message">{tweet.content}</div> // ์ •์˜๋œ fliterํ•จ์ˆ˜์˜ ๊ฐ’์„ ๋„ฃ๋Š”๋‹ค
              </div>
            </li>
              );
            })}
          </ul>
          TODO : Footer ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
          <Footer />
        </section>
      );
    };
    
    export default MyPage;

     

     

     

     

    ์‹คํ–‰ํ™”๋ฉด

     

    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€

Designed by Tistory.