Jieunny์ ๋ธ๋ก๊ทธ
S2) Unit 6. [์ค์ต] React Twittler State & Props ๋ณธ๋ฌธ
๐ฃ ๋ฆฌ์กํธ๋ก Twitter ๊ตฌํํ๊ธฐ
โ๏ธ react-router-dom ์ฌ์ฉํ๊ธฐ
โ๏ธ state & props ์ฌ์ฉํด์ ์ ์ก ํธ์ ๋ง๋ค๊ธฐ
โ๏ธ ๊ธฐ๋ณธ ํ์ด์ง ์ปดํฌ๋ํธ ๊ตฌํํ๊ธฐ
โ๏ธ font awesome ์ฌ์ฉํ๊ธฐ
๐ฃ ์ฃผ์ ์ปดํฌ๋ํธ
1๏ธโฃ App.js
import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
// TODO : React Router DOM์ ์ค์น ํ, import ๊ตฌ๋ฌธ์ ์ด์ฉํ์ฌ BrowserRouter, Routes, Route ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฌ์ต๋๋ค.
import Sidebar from './Sidebar';
import Tweets from './Pages/Tweets';
import MyPage from './Pages/MyPage';
import About from './Pages/About';
// 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 path="/about" element={<About />} />
<Route path="/mypage" element={<MyPage />} />
</Routes>
</section>
</main>
</div>
</BrowserRouter>
);
};
// ! ์๋ ์ฝ๋๋ ์์ ํ์ง ์์ต๋๋ค.
export default App;
โฐ BrowserRouter, Routes, Route ์ฌ์ฉํด์ ํน์ ๊ฒฝ๋ก์๋ ํน์ ์ปดํฌ๋ํธ๋ง ๋์ฐ๊ฒ ํ๋ค.
2๏ธโฃ Sidebar.js
import React from 'react';
import { Link } from 'react-router-dom';
// TODO : React Router DOM์ Link ์ปดํฌ๋ํธ๋ฅผ import ํฉ๋๋ค.
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;
โฐ font awesome ์ฌ์ฉํด์ ์์ด์ฝ ๋ถ๋ฌ์ค๊ณ , Route์ ๋์ผํ ๊ฒฝ๋ก๋ฅผ Link์ ์ค์ ํด์ ํ์ด์ง ์ด๋ ๊ฐ๋ฅํ๊ฒ ํ๊ธฐ
3๏ธโฃ 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 [inputText, setInputText] = useState('');
const [textareaContent, setTextareaContent] = useState('');
const [totalTweets, setTotalTweets] = useState(dummyTweets);
const handleButtonClick = (event) => {
const getRandomNumber = (min, max) => {
return parseInt(Math.random() * (Number(max) - Number(min) + 2));
};
const tweet = {
id: totalTweets.length+1,
username: inputText,
picture: `https://randomuser.me/api/portraits/women/${getRandomNumber(
1,
98
)}.jpg`,
content: textareaContent,
createdAt: new Date().toLocaleDateString('ko-kr'),
updateAt: new Date().toLocaleDateString('ko-kr')
};
// TODO : Tweet button ์๋ฆฌ๋จผํธ ํด๋ฆญ์ ์๋ํ๋ ํจ์๋ฅผ ์์ฑํ์ธ์.
// ํธ์ ์ ์ก์ด ๊ฐ๋ฅํ๊ฒ ์์ฑํด์ผ ํฉ๋๋ค.
setTotalTweets([tweet, ...totalTweets]);
};
const handleChangeUser = (event) => {
// TODO : Tweet input ์๋ฆฌ๋จผํธ์ ์
๋ ฅ ์ ์๋ํ๋ ํจ์๋ฅผ ์์ฑํ์ธ์.
setInputText(event.target.value);
};
const handleChangeMsg = (event) => {
// TODO : Tweet textarea ์๋ฆฌ๋จผํธ์ ์
๋ ฅ ์ ์๋ํ๋ ํจ์๋ฅผ ์์ฑํ์ธ์.
setTextareaContent(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"
placeholder="your username here.."
className="tweetForm__input--username"
onChange={handleChangeUser}
></input>
<textarea
placeholder="your text here.."
className="tweetForm__input--message"
onChange={handleChangeMsg}>
</textarea>
</div>
<div className="tweetForm__count" role="status">
<span className="tweetForm__count__text">
{/* TODO : ํธ์ ์ด ๊ฐ์๋ฅผ ๋ณด์ฌ์ค ์ ์๋ Counter๋ฅผ ์์ฑํ์ธ์. */}
{'total: ' + totalTweets.length}
</span>
</div>
</div>
<div className="tweetForm__submit">
<div className="tweetForm__submitIcon"></div>
{/* TODO : ์์ฑํ ํธ์์ ์ ์กํ ์ ์๋ button ์๋ฆฌ๋จผํธ๋ฅผ ์์ฑํ์ธ์. */}
<button
className="tweetForm__submitButton"
onClick={handleButtonClick}>์ ์ก
</button>
</div>
</div>
</div>
</div>
<div className="tweet__selectUser"></div>
<ul className="tweets">
{/* TODO : ํ๋์ ํธ์์ด ์๋๋ผ, ์ฃผ์ด์ง ํธ์ ๋ชฉ๋ก(dummyTweets) ๊ฐฏ์์ ๋ง๊ฒ ๋ณด์ฌ์ค์ผ ํฉ๋๋ค. */}
{totalTweets.map((tweet) => {
return <Tweet tweet={tweet} key={tweet.id} />
})}
</ul>
<Footer />
</React.Fragment>
);
};
export default Tweets;
โฐ useState() ์ฌ์ฉํด์ ๋๋ค์ ์ฐ๋ ์ ๋ ฅ์นธ, ํธ์ ๋ด์ฉ ์ฐ๋ ํ ์คํธ์นธ, ์ ์ฒด ํธ์ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํด์ค๋ค.
โฐ ์๋ก ํธ์์ ์ถ๊ฐํ๋ฉด ์ ์ฒด ํธ์์ด ๋์ด๋์ผ ํ๋ฏ๋ก, ์ ์ก ๋ฒํผ์ ๋๋ฅด๋ฉด ์ ์ฒด ํธ์ ๋ฐ์ดํฐ๊ฐ ์ถ๊ฐํ ํธ์์ด ๋ํด์ง ๋ฐ์ดํฐ๊ฐ ๋์ผํ๋ค.
โฐ ๋๋ค์ ์ ๋ ฅ์นธ, ํ ์คํธ ์ ๋ ฅ์นธ์ ์ฌ์ฉ์๊ฐ ์ ์ ๋๋ง๋ค ๋ณํด์ผ ํ๋ฏ๋ก, event ๊ฐ์ฒด๋ฅผ ์ด์ฉํด์ ๊ฐ์ ๋ฐ์์ค๊ณ , onChange์ ๊ทธ ํจ์๋ฅผ ์ ๋ฌํด์ค๋ค.
๐ฃ ์์ฐํ๋ฉด
'CodeStates > Training' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
S2) Unit 10. [์ค์ต] Mini Node Server (0) | 2023.02.06 |
---|---|
S2) Unit 9. [์ค์ต] StateAirline Client (0) | 2023.02.03 |
S2) Unit3. [์ค์ต] fetch API (0) | 2023.01.19 |
S2) Unit3. [์ค์ต] fs ๋ชจ๋ (0) | 2023.01.19 |
S2) Unit3. [์ค์ต] ํ์ด๋จธ API (0) | 2023.01.18 |