728x90
sidebar.js
import React from 'react';
import { Link } from 'react-router-dom';
const Sidebar = () => {
return(
<section className="sidebar">
<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;
/* 의사코드포함 */
import React from 'react';
import { Link } from 'react-router-dom';
//Link컴포넌트가 쓰일거라서 작성한다.
const Sidebar = () => {
return(
<section className="sidebar">
//사이드바에 밑의 아이콘들이 존재한다
<Link to="/"><i className="far fa-comment-dots"></i></Link>
//link는 to속성을 이용해서 path주소를 연결해준다.
//tweet아이콘의 link컴포넌트는 /으로 연결된다. 이게 첫화면이된다.
<Link to="/about"><i className="far fa-question-circle"></i></Link>
//about아이콘의 link컴포넌트는 /about으로 연결된다
<Link to="/mypage"><i className="far fa-user"></i></Link>
//mypage아이콘의 link컴포넌트는 /mypage으로 연결된다.
</section>
);
};
export default Sidebar; //import했으니까 마지막에 export해준다.
Footer
import React from 'react';
const Footer = () => {
return <footer></footer>;
//시멘틱요소 footer가 포함되었다
};
export default Footer;
Tweet
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">
<span className="tweet__username">{tweet.username}</span>
<span className="tweet__createdAt">{parsedDate}</span>
</div>
</div>
<div className="tweet__message">{tweet.content}</div>
</div>
</li>
);
};
export default Tweet;
/* 의사코드포함 */
import React from 'react';
import './Tweet.css';
//tweet.css 땡겨온다
//지금 이 tweet부분은 tweets중에서 한명의 내용이 뜨는 작은 컴포넌트이다.
const Tweet = ({ tweet }) => {
const parsedDate = new Date(tweet.createdAt).toLocaleDateString('ko-kr');
//날짜표기를 parsedDate라는 변수로 지정했다.
return (
<li className="tweet" id={tweet.id}>
<div className="tweet__profile"> //프로필부분에 사진이있다 그 사진이picture.
<img src={tweet.picture} />
</div>
<div className="tweet__content">
<div className="tweet__userInfo">
<div className="tweet__userInfo--wrapper"> //이박스에 이름과 날짜가 들어간다.
<span className="tweet__username">{tweet.username}</span>
<span className="tweet__createdAt">{parsedDate}</span> //위에서 지정한 변수를이용.
</div>
</div>
<div className="tweet__message">{tweet.content}</div>//더미데이터에서content부분이 메세지.
</div>
</li>
);
};
export default Tweet;
About
import React from 'react';
import Footer from '../Footer';
import './About.css';
const About = (props) => {
return (
<section className="aboutTwittler">
<div className="aboutTwittler__container">
<div className="aboutTwittler__wrapper">
<div className="aboutTwittler__detail">
<p className="aboutTwittler__detailName">React Twittler Info</p>
</div>
</div>
</div>
<div className="aboutTwittler__content">
<i className="fas fa-users"></i>
<p>나만의 Twittler 소개페이지를 꾸며보세요.</p>
</div>
<Footer />
</section>
);
};
export default About;
/* 의사코드포함 */
import React from 'react';
import Footer from '../Footer';
//about에서 footer파일은 한폴더 올라가야해서 ..
//하단에 footer시멘틱요소 하기위해 여기에 쓰고 저밑에 <Footer />한번더 쓴다
import './About.css';
//about css 불러온다.
const About = (props) => {
return (
<section className="aboutTwittler">
<div className="aboutTwittler__container">
<div className="aboutTwittler__wrapper">
<div className="aboutTwittler__detail">
<p className="aboutTwittler__detailName">React Twittler Info</p>
</div>
</div>
</div>
<div className="aboutTwittler__content">
<i className="fas fa-users"></i>
<p>나만의 Twittler 소개페이지를 꾸며보세요.</p>
</div>
<Footer />
//하단에 시멘틱footer요소위해 작성.
</section>
);
};
export default About;
Mypage
import React from 'react';
import Footer from '../Footer';
import Tweet from '../Components/Tweet';
import './MyPage.css';
import dummyTweets from '../static/dummyData';
const MyPage = () => {
// TODO : 주어진 트윗 목록(dummyTweets)중 현재 유져인 parkhacker의 트윗만 보여줘야 합니다.
const filteredTweets = dummyTweets.filter((tweet) => tweet.username === '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;
/* 의사코드포함 */
import React from 'react';
import Footer from '../Footer';
import Tweet from '../Components/Tweet';
//footer처럼 한폴더 위로 올라가서 components안에 들어가서 tweet있어서
import './MyPage.css';
import dummyTweets from '../static/dummyData';
//필터때 더미데이터가 쓰이니까 불러온다.
const MyPage = () => {
const filteredTweets = dummyTweets.filter((tweet) => tweet.username === 'parkhacker');
//더미데이터에서 username이 박해커인것만 골라낸다. 그게 filteredTweets이라는 변수가진다.
return (
<section className="myInfo">
<div className="myInfo__container">
<div className="myInfo__wrapper">
<div className="myInfo__profile">
<img src={filteredTweets[0].picture} />
//필터되서 박해커만 있으니까 인덱스는0이다.
</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]}/>
//앞의 tweet는 컴포넌트명(footer같은) 뒤의 tweet는 속성명이다.(classname같은거)
</ul>
<Footer />
//하단에 시멘틱요소
</section>
);
};
export default MyPage;
//이것으로 mypage를 마친다는 의미로 생각하면 될듯
Tweets
// 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 [tweets, setTweets] = useState(dummyTweets);
const [user, setUser] = useState("");
const [msg, setMsg] = useState("");
const handleButtonClick = (event) => {
const tweet = {
id: Tweets.length+1,
username: user,
picture: `https://randomuser.me/api/portraits/women/${getRandomNumber(
1,
98
)}.jpg`,
content: msg,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
// TODO : Tweet button 엘리먼트 클릭시 작동하는 함수를 완성하세요.
// 트윗 전송이 가능하게 작성해야 합니다.
setTweets([tweet, ...tweets])
setMsg(' ');
};
const handleChangeUser = (event) => {
// TODO : Tweet input 엘리먼트에 입력 시 작동하는 함수를 완성하세요.
setUser(event.target.value)
};
const handleChangeMsg = (event) => {
// TODO : Tweet textarea 엘리먼트에 입력 시 작동하는 함수를 완성하세요.
setMsg(event.target.value)
};
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"
placeholder="your username here.."
className="tweetForm__input--username"
onChange= {handleChangeUser}
value={user}
></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) => <Tweet tweet ={el}/>)}
</ul>
<Footer />
</React.Fragment>
);
};
export default Tweets;
/* 의사코드포함 */
import React, { useState } from 'react';
//useState사용하기위해 react로부터 불러왔다.
import Footer from '../Footer';
import Tweet from '../Components/Tweet';
import './Tweets.css';
import dummyTweets from '../static/dummyData';
const Tweets = () => {
const getRandomNumber = (min, max) => {
return parseInt(Math.random() * (Number(max) - Number(min) + 2));
};
const [tweets, setTweets] = useState(dummyTweets);
//기존이tweets, 새로운내용추가되면 setTweets.
const [user, setUser] = useState("");
//user가 state변수, setUser는 변수를 갱신할수있는함수이다. 초기값은 비어있다.
const [msg, setMsg] = useState("");
const handleButtonClick = (event) => {
const tweet = {
id: Tweets.length+1,
username: user,
picture: `https://randomuser.me/api/portraits/women/${getRandomNumber(1,98)}.jpg`,
content: msg,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
setTweets([tweet, ...tweets])
//빈배열에다가 기존tweets를 넣고 spread문법을쓰고, 새로운것도 추가한다는거다.
//기존의 데이터가tweets다. 새로운 tweet가 위에 위치한다.
setMsg(' ');
//이거랑 value=msg도 추가하면 입력하고 엔터치면 입력창 깨끗해지는 기능한다.
};
const handleChangeUser = (event) => {
setUser(event.target.value)};
//target은 input태그가 된다. 이벤트가 발생하는 엘리먼트의 값을 가져온다
//value안쓰면 input문장을 가져온다
const handleChangeMsg = (event) => {
setMsg(event.target.value)}; //target은 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"
placeholder="your username here.."
className="tweetForm__input--username"
onChange= {handleChangeUser}
//onchange이벤트가 발생하면 setUser된 input값을 불러온다.
value={user}
></input>
<textarea
defaultValue={""}
placeholder="your message here.."
className="tweetForm__input--message"
onChange= {handleChangeMsg}
//onChange이벤트가 발생하면 setMsg된 textarea값을 불러온다.
value={msg}
//이거추가하면 입력창 깨끗해진다!
></textarea>
</div>
<div className="tweetForm__count" role="status">
<span className="tweetForm__count__text">
{'total: ' + tweets.length}
//tweets의 총 개수를 보여준다.
</span>
</div>
</div>
<div className="tweetForm__submit">
<div className="tweetForm__submitIcon"></div>
<button className="tweetForm__submitButton" onClick={handleButtonClick}>Tweet</button>
//Tweet버튼을 클릭하면 handleButtonClick함수가 작동한다.
</div>
</div>
</div>
</div>
<div className="tweet__selectUser"></div>
<ul className="tweets">
{tweets.map((el) => <Tweet tweet ={el}/>)}
//앞의tweet은컴포넌트명이고 뒤의 tweet은 속성명이다
</ul>
<Footer />
</React.Fragment>
);
};
export default Tweets;
App.js
import React from 'react';
// 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';
import About from './Pages/About';
import MyPage from './Pages/MyPage';
// TODO : MyPage, About 컴포넌트를 import 합니다.
import './App.css';
import './global-style.css';
const App = (props) => {
return (
<BrowserRouter>
<div className="App">
<main>
<Sidebar />
<section className="features">
{/* TODO : 유어클래스를 참고해서, 테스트 케이스를 통과하세요.
TODO : React Router DOM 설치 후 BrowserRouter, Routes, Route의 주석을 해제하고 Routes, Route 컴포넌트를 적절하게 작성합니다. */}
{/* Route 예시: <Route path="/" element={<Tweets />}></Route> */}
<Routes>
<Route path="/" element={<Tweets />}></Route>
<Route path="/about" element={<About />}></Route>
<Route path="/mypage" element={<MyPage />}></Route>
</Routes>
</section>
</main>
</div>
</BrowserRouter>
);
};
// ! 아래 코드는 수정하지 않습니다.
export default App;
/* 의사코드포함 */
import React from 'react';
import {BrowserRouter, Routes, Route } from 'react-router-dom';
//react router의 컴포넌트들(browserrouter, routes, route)을 사용하기위해 불러온다.
import Sidebar from './Sidebar';
import Tweets from './Pages/Tweets';
import About from './Pages/About';
import MyPage from './Pages/MyPage';
import './App.css';
import './global-style.css';
const App = (props) => {
return (
<BrowserRouter>
//browserRouter컴포넌트를사용할거다
<div className="App">
<main>
<Sidebar />
//이거랑 import에서 sidebar부분 지우면 아예 앱에서 sidebar사라진다
<section className="features">
<Routes>
//routes는 route를 감싸고있어야한다.
<Route path="/" element={<Tweets />}></Route>
<Route path="/about" element={<About />}></Route>
//about메뉴를 누르면 path가 about으로 연결된다.
<Route path="/mypage" element={<MyPage />}></Route>
//Mypage메뉴를 누르면 path가 /mypage로 연결된다.
</Routes>
</section>
</main>
</div>
</BrowserRouter>
);
};
export default App;
route컴포넌트는 path속성을 지정하여 해당 path에서 어떤 컴포넌트를 보여줄지 정한다. 근데 path가 /mypage여서 MyPage컴포넌트로 연결이 된다.
Link컴포넌트가 정해주는 url경로와 일치하는 경우에만 작동한다.
route태그안에 element속성으로 연결하고자 하는 컴포넌트를 넣어준다.
저기서는 그 컴포넌트가 MyPage였던거고 Tweets였던거.
path와 Link to가 일치하면 i className을 누르면 element컴포넌트(Tweets)로 연결이된다.
728x90