sprint - twittler state & props

FeelSoo·2022년 4월 12일
1

CodeStates

목록 보기
10/43

Bareminimum

React Router 설치
-- React Router DOM을 npm 으로 설치해야 합니다.

상세 컴포넌트 구현하기
원하는 레이아웃에 끼워넣을 수 있게 상세 컴포넌트를 먼저 구현합니다.

Sidebar 컴포넌트 (Sidebar.js)
-- Sidebar 컴포넌트는 이미 구현되어 있습니다. Sidebar.js 파일에서 직접 확인하세요.
Footer 컴포넌트 (Footer.js)
- Footer 컴포넌트의 후손 엘리먼트로 시멘틱 엘리먼트 <footer>가 있어야 합니다.
Tweet 컴포넌트 (Tweet.js)
-- 각 트윗에 꼭 필요한 정보를 담고 있어야 합니다. (프로필 사진, 유저 이름, 트윗 생성 일자, 트윗 메세지)
-- 프로필 사진을 넣기 위해 <img> 엘리먼트를 작성하고, src 속성에 전달받은 props의 사진 정보를 넣습니다.
-유저 이름을 넣기 위해 <span>엘리먼트를 작성하고, class 이름을 tweet__username로 지정하세요.
-- 트윗 생성 일자를 넣기 위해 <span>엘리먼트를 작성하고, class 이름을 tweet__createdAt으로 지정하세요.
-- 날짜 형식은 yyyy. mm. dd. 이어야 하고, parsedDate 변수를 이용하세요.
-- 트윗 메세지를 넣기 위해 <div>엘리먼트를 작성하고, class 이름을 tweet__message로 지정하세요.
-- dummyTweets가 아닌 다른 데이터가 props로 전달 되어도 트윗 정보를 정확하게 표시해야 합니다.

페이지 컴포넌트 구현하기
-페이지를 구성하는 컴포넌트를 작성합니다.

이번 스프린트의 현재 유져는 parkhacker이기 때문에, 트위틀러의 My Page에서 parkhacker의 트윗만 보여야 하는 요구사항을 만족해야 합니다.

About 컴포넌트 (About.js)
-- About 컴포넌트의 자식 컴포넌트로 Footer 컴포넌트가 있어야 합니다.
MyPage 컴포넌트 (MyPage.js)
-- 주어진 트윗 목록(dummyTweets)중 현재 유저인 parkhacker의 트윗만 보여야 합니다.
-- MyPage 컴포넌트의 자식인 Tweet 컴포넌트에 props로 각 트윗의 정보(dummyTweets의 요소)가 전달되어야 합니다.
-- MyPage 컴포넌트의 자식 컴포넌트로 Footer 컴포넌트가 있어야 합니다.
Tweets 컴포넌트 (Tweets.js)
-- 하나의 트윗이 아니라, 주어진 트윗(dummyTweets) 개수에 맞게 보여줘야 합니다. (11 ms)
-- Tweets 컴포넌트의 자식 컴포넌트로 Footer 컴포넌트가 있어야 합니다. (4 ms)

React Router 적용하기
이전 React Twittler SPA Sprint 에서 배운 내용을 바탕으로 아래 기술 요구사항을 구현합니다.

React Router 컴포넌트 적용
Route path가 "/" 인 Tweets 컴포넌트가 있어야 합니다.
Route path가 "/about" 인 About 컴포넌트가 있어야 합니다.
Route path가 "/mypage" 인 MyPage 컴포넌트가 있어야 합니다.
React Router의 Link 컴포넌트가 3개 있어야 합니다.
Tweets 아이콘의 Link 컴포넌트는 "/" 로 연결되어야 합니다.
About 아이콘의 Link 컴포넌트는 "/about" 로 연결되어야 합니다.
MyPage 아이콘의 Link 컴포넌트는 "/mypage" 로 연결되어야 합니다.
React Router로 SPA 구현하기
-- 처음 접속 시, URL path가 / 이여야 합니다.
-- About 메뉴를 누르면 URL path가 /about으로 라우트 되어야 합니다.
-- Mypage 메뉴를 누르면 URL path가 /mypage로 라우트 되어야 합니다.
-- State, Props 활용 트윗 전송 Form 만들기

이번 스프린트의 핵심입니다. Tweets 컴포넌트에서 어떤 데이터가 state가 되어야 하고, 어떤 데이터를 props로 하위 컴포넌트에 전달해야 할지 고민하고 아래 기술 요구사항을 구현합니다. State, Props 레슨과 실습이 도움이 될겁니다. 😇

Tweets.js 트윗 전송 Form 테스트

유저 이름을 작성할 수 있는 input 엘리먼트가 있어야 합니다. (className : "tweetForm__input--username")
트윗을 작성할 수 있는 textarea 엘리먼트가 있어야 합니다. (className : "tweetForm__input--message")
트윗을 전송할 수 있는 button 엘리먼트가 있어야 합니다.
유저 이름과 트윗을 작성하고, 트윗 버튼을 누르면 새로운 트윗이 추가되어야 합니다.
기존 dummyTweets 를 모두 보여줘야 합니다.
새로 추가된 트윗을 포함하여 보여줘야 합니다.
새로 추가된 트윗이 최상단에 위치하여야 합니다.

App.js

import React from 'react';
// TODO : React Router DOM을 설치 후, import 구문을 이용하여 BrowserRouter, Route, Switch 컴포넌트를 불러옵니다.
import {BrowserRouter, Route, Switch, Link} from 'react-router-dom';
import Sidebar from './Sidebar';
import Tweets from './Pages/Tweets';
// TODO : MyPage, About 컴포넌트를 import 합니다.
import MyPage from './Pages/MyPage';
import About from './Pages/About' ;
import './App.css';

const App = (props) => {
  return (
    <BrowserRouter>
      <div className="App">
        <main>
          <Sidebar />
          <section className="features">
            <Switch>
              <Route exact path="/">
                <Tweets />
              </Route>

              <Route path="/about">
                <About />
              </Route>

              <Route path="/mypage">
                <MyPage />
              </Route>
              
            </Switch>
            {/* TODO : 유어클래스를 참고해서, 테스트 케이스를 통과하세요.
            TODO : React Router DOM 설치 후 BrowserRouter, Route의 주석을 해제하고 Swtich 컴포넌트를 적절하게 작성합니다. */}
          </section>
        </main>
      </div>
    // </BrowserRouter>
  );
};

// ! 아래 코드는 수정하지 않습니다.
export default App;



Sidebar.js

import React from 'react';
// TODO : React Router DOM의 Link 컴포넌트를 import 합니다.
import { Link } from 'react-router-dom';

const Sidebar = () => {
  return (
    <section className="sidebar">
      {/* TODO : Link 컴포넌트를 작성하고, to 속성을 이용하여 경로(path)를 연결합니다. */}
      <Link to="/"><i className="far fa-comment-dots"></i></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;



Footer.js

import React from 'react';

const Footer = () => {
  
  return <footer>copyright from Codestates</footer>
};
// TODO : Footer 함수 컴포넌트를 작성합니다. 시멘틱 엘리먼트 footer가 포함되어야 합니다.

export default Footer;



Tweets.js

// TODO : useState를 react로 부터 import 합니다.
import React, { useState } from 'react';
import Footer from '../Footer';
import Tweet from '../Components/Tweet';
import './Tweets.css';
import dummyTweets from '../static/dummyData';

const Tweets = () => {
  // TODO : 새로 트윗을 작성하고 전송할 수 있게 useState를 적절히 활용하세요.
  
  const getRandomNumber = (min, max) => {
    return parseInt(Math.random() * (Number(max) - Number(min) + 2));
  };
  
  const [user, setUser] = useState('parkhacker');
  const [msg, setMsg] = useState('');
  const [tweets, setTweets] = useState(dummyTweets);
  
  const handleButtonClick = (event) => {
    const tweet = {
      id: dummyTweets.length,
      username: user,
      picture: `https://randomuser.me/api/portraits/women/${getRandomNumber(
        1,
        98
      )}.jpg`,
      content :msg,
      createdAt : new Date().toLocaleDateString('ko-kr'),
      updatedAt : new Date().toLocaleDateString('ko-kr'),
      

    };
    // TODO : Tweet button 엘리먼트 클릭시 작동하는 함수를 완성하세요.
    // 트윗 전송이 가능하게 작성해야 합니다.
    setTweets([tweet, ...tweets])
  };
  

  const handleChangeUser = (event) => {
    setUser(event.target.value)
    // TODO : Tweet input 엘리먼트에 입력 시 작동하는 함수를 완성하세요.
  };

  const handleChangeMsg = (event) => {
    setMsg(event.target.value)
    // TODO : Tweet textarea 엘리먼트에 입력 시 작동하는 함수를 완성하세요.
  };

  return (
    <React.Fragment>
      <div className="tweetForm__container">
        <div className="tweetForm__wrapper">
          <div className="tweetForm__profile">
            <img src="https://randomuser.me/api/portraits/men/98.jpg" />
          </div>
          <div className="tweetForm__inputContainer">
            <div className="tweetForm__inputWrapper">
              <div className="tweetForm__input">


                <input
                  type="text"
                  defaultValue="parkhacker"
                  value={user}
                  placeholder="your username here.."
                  className="tweetForm__input--username"
                  onChange={handleChangeUser}
                ></input>
                TODO : 트윗을 작성할 수 있는 textarea 엘리먼트를 작성하세요.
              
              
              <textarea

                defaultValue={""}
                placeholder="your message here.."
                className="tweetForm__input--message"
                onChange={handleChangeMsg}
                value={msg}

              ></textarea></div>


              <div className="tweetForm__count" role="status">
                <span className="tweetForm__count__text">
                  {/* TODO : 트윗 총 개수를 보여줄 수 있는 Counter를 작성하세요. */}
                  {'total: ' + tweets.length}
                </span>
              </div>
            </div>


            <div className="tweetForm__submit">
              <div className="tweetForm__submitIcon"></div>
              {/* TODO : 작성한 트윗을 전송할 수 있는 button 엘리먼트를 작성하세요. */}
              <button className="tweetForm__submitButton" onClick={handleButtonClick}>Tweet</button>
            </div>
          </div>
        </div>
      </div>


      <div className="tweet__selectUser"></div>
      <ul className="tweets">
        {/* TODO : 하나의 트윗이 아니라, 주어진 트윗 목록(dummyTweets) 갯수에 맞게 보여줘야 합니다. */}
        {tweets.map((el) => { 
          return (
            <Tweet tweet={el} />
          )})}

      </ul>
      <Footer />
    </React.Fragment>
  );
};

export default Tweets;



Mypage.js

import React from 'react';
import Footer from '../Footer';
import Tweet from '../Components/Tweet';
import './MyPage.css';
import dummyTweets from '../static/dummyData';

const MyPage = () => {
  const filteredTweets = dummyTweets.filter((tweet) => {
    return tweet.username === 'parkhacker';
  })
  // TODO : 주어진 트윗 목록(dummyTweets)중 현재 유져인 parkhacker의 트윗만 보여줘야 합니다.

  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">
        <Tweet tweet={filteredTweets[0]}/>
        {/* TODO : 주어진 트윗 목록(dummyTweets)중 현재 유져인 parkhacker의 트윗만 보여줘야 합니다. */}
      </ul>
      <Footer />
    </section>
  );
};

export default MyPage;



Tweet.js

import React from 'react';
import './Tweet.css';

const Tweet = ({ tweet }) => {
  const parsedDate = new Date(tweet.createdAt).toLocaleDateString('ko-kr');

  return (
    <li className="tweet" id={tweet.id}>
      <div className="tweet__profile">
        <img src={tweet.picture} />
      </div>
      <div className="tweet__content">
        <div className="tweet__userInfo">
          <div className="tweet__userInfo--wrapper">
            {/* TODO : 유져 이름이 있어야 합니다. */}
            {/* TODO : 트윗 생성 일자가 있어야 합니다. parsedDate를 이용하세요. */}
            <span className="tweet__username">{tweet.username}</span>
            <span className="tweet__createdAt">{parsedDate}</span>
          </div>
        </div>
        <div className="tweet__message">
          {/* TODO : 트윗 메세지가 있어야 합니다. */}
         {tweet.content}
        </div>
      </div>
    </li>
  );
};

export default Tweet;

profile
세상은 넓고 배울건 많다

0개의 댓글