{/* 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>
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>
{/* TODO : 유져 이름이 있어야 합니다. */}
{/* TODO : 트윗 생성 일자가 있어야 합니다. parsedDate를 이용하세요. */}
<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 Footer from '../Footer';
import Tweet from '../Components/Tweet';
import './MyPage.css';
import dummyTweets from '../static/dummyData';
const MyPage = () => {
const filteredTweets = dummyTweets;
// TODO : 주어진 트윗 목록(dummyTweets)중 현재 유져인 parkhacker의 트윗만 보여줘야 합니다.
return (
<section className="myInfo">
<div className="myInfo__container">
<div className="myInfo__wrapper">
<div className="myInfo__profile">
<img src={filteredTweets[1].picture} />
</div>
<div className="myInfo__detail">
<p className="myInfo__detailName">
{filteredTweets[1].username} Profile
</p>
<p>28 팔로워 100 팔로잉</p>
</div>
</div>
</div>
<ul className="tweets__mypage">
<Tweet tweet={filteredTweets[1]}/>
</ul>
<Footer />
</section>
);
};
export default MyPage;
-- ✓ MyPage 컴포넌트의 자식인 Tweet 컴포넌트에 props로 각 트윗의 정보(dummyTweets의 요소)가 전달되어야 합니다. (2 ms)--라는 조건이 잇음에도 불구하고 전처럼 하나하나 적으려고 함또한 여기서 --주어진 트윗 목록(dummyTweets) 중 현재 유저인 parkhacker의 트윗만 보여야 합니다. (4 ms)-- 중 filter를 써서 하려고 했는데 이미 tweet.js안에 [1]인 것만 리턴을 해서 안해준듯 하다 !!!!레퍼런스를 보니< Tweet tweet={filteredTweets[1]}/> 맨처음 Tweet는 자식컴포넌트의 이름이고 tweet는 props이다!
로 해도 실행이 되는 걸 볼 수있었다.const filteredTweets = dummyTweets.filter(tweet => tweet.username === 'parkhacker');
{filteredTweets.map(tweet => {
return < Tweet tweet={tweet} key={tweet.id}>
})}
내가 쓴 것과 달리 map을 써서 해당되는 id값을 보내준 것 같다 아마 위에는 필터로 했으나 밑에서 막혀 실행이 안됬던 거로 보인다
중요한점은 key값이 있어야 고유값이 있어 돌릴 수 있는 것 같다.
코드를 입력하세요// 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[newTweet , setnewTweet] = useState(""); //이름을 넣을때 사용인데 좀 더 명확하게 바꾸기
const[newcontent, setnewContent] = useState(""); //내용
const[tweets,setTweet] =useState(dummyTweets);//데이터
const[opt ,setOpt] = useState(options)
const[clickedName,setClickedName] = useState("")
const [filteredUser, setFilteredUser] =useState(tweets);
// const getRandomNumber = (min, max) => {
// return parseInt(Math.random() * (Number(max) - Number(min) + 2));
// };
const options = [{value:"kimcoding",label:"kimcoding"},
{value:"parkhacker",label:"parkhacker"},
{value:"leedesign",label:"leedesign"},
{value:"songfront",label:"songfront"},
{value:"choiback",label:"choiback"}];
const handleDeleteClick = (event) => {
setTweet(tweets.filter((el) => { return el.id !== Number(event.target.attributes.id.value);}))}
const handleSelectClick = (event) => {
setClickedName(event.target.value)
setFilteredUser(tweets.filter((el)=>{return el.username === event.target.value;}))
};
const handleButtonClick = (event) => {
//버튼을 누르면 새로운 내용이 추가되어야 하는 것 이건 dom의 이벤트핸들러와 비슷하다
const tweet = {
id : tweets.length+1,(더미데이터의 갯수 +1)
username: newTweet,
picture:`https://randomuser.me/api/portraits/men/98.jpg`, 랜덤이미지?
content:newcontent,
createdAt: new Date(),//현재시간
updateAt: new Date(),
};
setTweet([tweet,...tweets])//지금 추가한 내용 + 원래더미데이터의 내용
};
<button onClick={handleButtonClick}>Tweets</button>
const handleChangeUser = (event) => {
// TODO : Tweet input 엘리먼트에 입력 시 작동하는 함수를 완성하세요.
setnewTweet(event.target.value)
};
const handleChangeMsg = (event) => {
// TODO : Tweet textarea 엘리먼트에 입력 시 작동하는 함수를 완성하세요.
setnewContent(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}
></input>
{/* TODO : 트윗을 작성할 수 있는 textarea 엘리먼트를 작성하세요. */}
<textarea
type ="text"
className="tweetForm__input--message"
onChange={handleChangeMsg}
value={newcontent}>
</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>
<button className = "tweetForm__submitButton" onClick={handleButtonClick}>Tweet</button>
{/* TODO : 작성한 트윗을 전송할 수 있는 button 엘리먼트를 작성하세요. */}
</div>
</div>
</div>
</div>
<div className="tweet__selectUser">
<select
newTweet = "users" id = "user_select"
onChange = {handleSelectClick}>
<option value = "">-- click to filter tweets by username --</option>
{opt.map((el) => {return <option value = {el.value} key = {el.value}>{el.label}</option> })}
</select>
</div>
{clickedName === "" ? tweets.map((el) => {return <Tweet tweet={ el } key = {el.id} handleDeleteClick = {handleDeleteClick} /> })
: filteredUser.map((el) => {return <Tweet tweet={ el } key = {el.id} />})
}
<ul className="tweets">
{/* TODO : 하나의 트윗이 아니라, 주어진 트윗 목록(dummyTweets) 갯수에 맞게 보여줘야 합니다. */}
// 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[newTweet , setnewTweet] = useState(""); //애매
const[newcontent, setnewContent] = useState("");
const[tweets,setTweet] =useState(dummyTweets);
const[opt ,setOpt] = useState(options)
const[clickedName,setClickedName] = useState("")
const [filteredUser, setFilteredUser] =useState(tweets);
// const getRandomNumber = (min, max) => {
// return parseInt(Math.random() * (Number(max) - Number(min) + 2));
// };
const options = [{value:"kimcoding",label:"kimcoding"},
{value:"parkhacker",label:"parkhacker"},
{value:"leedesign",label:"leedesign"},
{value:"songfront",label:"songfront"},
{value:"choiback",label:"choiback"}];
const handleDeleteClick = (event) => {
setTweet(tweets.filter((el) => { return el.id !== Number(event.target.attributes.id.value);}))}
const handleSelectClick = (event) => {
setClickedName(event.target.value)
setFilteredUser(tweets.filter((el)=>{return el.username === event.target.value;}))
};
const handleButtonClick = (event) => {
const tweet = {
id : tweets.length+1,
username: newTweet,
picture:`https://randomuser.me/api/portraits/men/98.jpg`,
content:newcontent,
createdAt: new Date(),
updateAt: new Date(),
};
setTweet([tweet,...tweets])
};
<button onClick={handleButtonClick}>Tweets</button>
const handleChangeUser = (event) => {
// TODO : Tweet input 엘리먼트에 입력 시 작동하는 함수를 완성하세요.
setnewTweet(event.target.value)
};
const handleChangeMsg = (event) => {
// TODO : Tweet textarea 엘리먼트에 입력 시 작동하는 함수를 완성하세요.
setnewContent(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}
></input>
{/* TODO : 트윗을 작성할 수 있는 textarea 엘리먼트를 작성하세요. */}
<textarea
type ="text"
className="tweetForm__input--message"
onChange={handleChangeMsg}
value={newcontent}>
</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>
<button className = "tweetForm__submitButton" onClick={handleButtonClick}>Tweet</button>
{/* TODO : 작성한 트윗을 전송할 수 있는 button 엘리먼트를 작성하세요. */}
</div>
</div>
</div>
</div>
<div className="tweet__selectUser">
<select
newTweet = "users" id = "user_select"
onChange = {handleSelectClick}>
<option value = "">-- click to filter tweets by username --</option>
{opt.map((el) => {return <option value = {el.value} key = {el.value}>{el.label}</option> })}
</select>
</div>
{clickedName === "" ? tweets.map((el) => {return <Tweet tweet={ el } key = {el.id} handleDeleteClick = {handleDeleteClick} /> })
: filteredUser.map((el) => {return <Tweet tweet={ el } key = {el.id} />})
}
<ul className="tweets">
{/* TODO : 하나의 트윗이 아니라, 주어진 트윗 목록(dummyTweets) 갯수에 맞게 보여줘야 합니다. */}
{tweets.map((tweet) => <Tweet tweet={tweet}/> )}
</ul>
<Footer />
</React.Fragment>
);
}
export default Tweets;
</ul>
<Footer />
</React.Fragment>
);
}
export default Tweets;
힘들었던 곳 --✓ 하나의 트윗이 아니라, 주어진 트윗(dummyTweets) 개수에 맞게 보여줘야 합니다. (50 ms)--
{tweets.map((tweet) => < Tweet tweet={tweet}/> )}
map을 쓰는 것 까지는 이해를 했으나 앞에 dummydate tweets로 선언해주었는데 그대로 dummydata를 써서 안된듯 하다
데이터를 추가하는 handleButtonClick이벤트에서 마지막에 데이터를 앞에 넣을때
// tweets.unshift(tweet);
// setTweets(tweets);
일때 문제가 생긴다 왜냐 얕은 복사라 1번째의 tweets와 두번째의 tweets는 같은 주소라 리렌더링을 하지않기 때문이다!
중요한점!
이번 과제의 핵심입니다. Tweets 컴포넌트에서 어떤 데이터가 state가 되어야 하고, 어떤 데이터를 props로 하위 컴포넌트에 전달해야 할지 고민하고 아래 기술 요구사항을 구현합니다.
state 인것