오늘의 학습내용
: 컴포넌트 내부에서 변할 수 있는 값
import { useState } from "react";
const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);
function CheckboxExample() {
const [isChecked, setIsChecked] = useState(false);
const handleChecked = (event) => {
setIsChecked(event.target.checked);
};
return (
<div className="App">
<input type="checkbox" checked={isChecked} onChange={handleChecked} />
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
</div>
);
}
: input/textarea/select 와 같은 폼(Form) 엘리먼트에 주로 사용함. 'e.target.value' 를 통해 이벤트 객체에 담겨있는 input 값을 읽어올 수 있음.
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
<h1>{name}</h1>
</div>
)
};
: 클릭 시 이벤트 발생. onClick 이벤트에 함수를 바로 호출하면 함수가 아닌 함수의 결과값이 호출되기 때문에 undefined를 반환함. 따라서 리턴문 안에서 함수를 정의하거나 리턴문 밖에서 함수를 정의하고 전달해야 함. 이때 함수는 arrow function으로 작성해야 함.
const handleClick = () => {
alert(name);
};
return (
<div>
...
<button onClick={handleClick}>Button</button>
...
</div>
);
: 외부로부터 전달 받은 변하지 않는 값
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
<Child>I'm the eldest child</Child>
</div>
);
};
function Child(props) {
return (
<div className="child">
<p>{props.children}</p>
</div>
);
};
Github URL : https://github.com/wongee93/fe-sprint-react-twittler-state-props
'Parkhacker'의 Mypage 불러오기
지난번과 동일한 방식으로 필터링을 통해 박해커의 유저정보를 가져온 후, map()을 써서 뿌리는 것까지는 생각이 났는데 어떻게 뿌려줄 지 한참 고민에 고민을 거듭했었다. map()안에 'Tweet'태그를 써서 Tweet.js에서 만들어준 컴포넌트를 뿌려주었더니 성공하였다. 태그의 key를 지정하고 tweet = {tweet}을 이용하여 전체 정보를 가져올 수 있다.
const MyPage = () => {
const filteredTweets = dummyTweets.filter((x) => {
if (x.username === 'parkhacker') {
return x;
}
});
return (
<section className="myInfo">
{filteredTweets.map((tweet) => {
return <Tweet key ={tweet.id} tweet = {tweet} />
})}
</ul>
<Footer />
</section>
);
트윗 메시지 업로드 기능 추가하기
새로운 트윗을 추가하기 위한 username창(input)과 메시지창(textarea) 그리고 추가버튼 기능을 만들어주었다.
해당 정보들은 유저들의 입력 상태나 이벤트로 바뀔 수 있는 값들이기 때문에 상태관리를 위해 state 속성을 이용하여 이를 관리해주어야 한다. username창은 박해커의 트윗으로 셋팅해주어야 하는 상황이기 때문에 초기값을 'parkhacker' 로 지정하였다. 추가로 Tweets 화면에 렌더링되는 부분도 트윗이 추가됨에 따라 상태가 바뀌기 때문에 useState를 적용하였고 초기값은 dummyTweets로 지정해주었다.
새로운 내용을 입력하고 'Tweet'버튼을 누르면 작성한 내용과 함께 새로운 트윗이 추가되어야하고 이를 위해선 버튼에 이벤트 로직을 적용해야 한다.
이 부분에서 애를 먹었는데, 우선 새로 추가되는 트윗의 요소를 Tweet 컴포넌트 구성에 맞추어 속성을 지정해주어야 한다. 그리고 이를 배열에 추가해주어야 하는데 Spread syntax를 사용하였다. newTweets라는 새로운 배열을 생성한 후(dummyTweets 얕은 복사), ...tweets로 dummyTweets의 요소들을 넣어주고 맨 앞에 parkhacker가 입력한 textarea 내용을 tweet 컴포넌트 형태로 출력하여 넣어주는 로직을 handleButtonClick 이벤트에 적용하였다.
const Tweets = () => {
const [username, setUsername] = useState("parkhacker");
const [msg, setMsg] = useState("");
const [tweets, setTweets] = useState(dummyTweets)
const handleButtonClick = (event) => {
const tweet = {
id: tweets.length + 1,
username: username,
picture: `https://randomuser.me/api/portraits/men/98.jpg`,
content: msg,
ceratedAt: new Date().toLocaleDateString('ko-kr'),
updatedAt: new Date().toLocaleDateString('ko-kr')
};
const newTweets = [tweet, ...tweets];
setTweets(newTweets);
// ```
const handleChangeMsg = (event) => {
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">
{/* 생략 */}
<textarea
value={msg}
onChange={handleChangeMsg}
placeholder="your username here"
className='tweetForm__input--message'
></textarea>
{/* 생략 */}
<div className="tweetForm__submit">
<div className="tweetForm__submitIcon"></div>
<button className='tweetForm__submitButton' onClick={handleButtonClick}>Tweet</button>
</div>
<ul className="tweets">
{tweets.map(tweet => {
return (<Tweet key={tweet.id} tweet={tweet} />)
})}
</ul>
<Footer />
</React.Fragment>
);
}
export default Tweets;
setTweets(newTweets);