State : 변할 수 있는 것, 컴포넌트 내부에서 변화 가능
Props : 외부로 부터 전달받은 값
<Human />
컴포넌트의 state와 props
property, 상위 컴포넌트로부터 전달받은 값으로 변하지 않음
object 형태
읽기 전용, 단방향, 하향식 데이터 흐름 원칙을 지켜야 함.
사용법
{...someObj}
형식으로 전달해야한다.<Child attribute={value} />
function Child(props) {
return (
<div className="child"></div>
);
};
리액트에서 state를 다루기 위해 useState(<initVal>)
라는 함수를 활용한다.
상태값이 primitive value와 객체인 경우에 setState하는 방식이 다름을 잘 기억하자.
objState = {...objState, newElem}
arrState = [...arrState, newElem}
리액트의 가상 DOM은 '차이점'을 기준으로 렌더링 한다.
객체는 포인터로 저장되고, Array.prototype.push
등의 메서드는
포인터를 변화시키지 않으므로, 상태변화를 리액트가 인지하지 못하기 때문이다.
import { useState } from "react";
// 풀어쓴 코드
const stateHookArray = useState(false);
const isChecked = stateHookArray[0];
const setIsChecked = stateHookArray[1];
// 구조분해 할당을 통한 단축코드
const [isChecked, setIsChecked] = useState(false);
항상 상태변경 함수 호출로 상태변경해야한다.
import React, { useState } from "react";
import "./styles.css";
function App() {
const [showPopup, setShowPopup] = useState(false);
const togglePopup = (event) => {
console.log(showPopup);
setShowPopup(!showPopup);
};
return (
<div className="App">
<h1>Fix me to open Pop Up</h1>
<button className="open" onClick={togglePopup}>
Open me
</button>
{showPopup ? (
<div className="popup">
<div className="popup_inner">
<h2>Success!</h2>
<button className="close" onClick={togglePopup}>
Close me
</button>
</div>
</div>
) : null}
</div>
);
}
export default App;
반복문을 통해 생성하는 컴포넌트에 key 속성을 넣는 것 잊지 않기
어떤 컴포넌트를 대상으로 state, props관리를 해야되는지 잘 고려하기
//main 컴포넌트
import { dummyTweets } from './dummyData';
import SingleTweet from './SingleTweet';
function Main() {
return (
<div className='Main'>
<ul>
{dummyTweets.map(elem => <SingleTweet key={elem.id} value={elem} />)}
</ul>
</div>
);
}
export default Main;
// 상태관리와 이벤트리스너가 적용된 singleTweet 컴포넌트
import React, { useState } from 'react';
function SingleTweet(props) {
const [isActive, setActive] = useState(true);
const handleTweetClick = (event => {
console.log(event);
setActive(!isActive);
});
const { item_id, username, content } = props.value;
return (
<div style={{
border: "solid 1px black",
backgroundColor: isActive ? 'green' : 'gray'
}} className='singleTweet' onClick={handleTweetClick}>
<p>{item_id} </p>
<p>{username} </p>
<p>{content} </p>
</div>
);
}
export default SingleTweet;
velog 서버가 잠시 터져서 vscode 설정을 업데이트 했다.
<leader><leader> + <w|b|f|F>
입력하면 vimium에서 점프하는 것처럼 이동가능.스프린트 테스트에 오류가 있어 잠깐 멘붕했지만, 그래도 쭈욱 advanced까지 구현해보았다.
arr = [{name:"kim", age:20}, {name:"lee", age:50}]
arr.map(elem => elem.name) ["kim", "lee"]
데이터의 길이로 키를 설정하니 삭제시 문제발생함.
Date.now();// 1664196074967
옵션으로 필터링하는 기능
함수를 분리해도 되지만 간단히 한번만 사용할 로직이므로 인라인함수로 넣었다.
일부러 배운 내용을 활용하기 위해 reduce
를 활용해서 구현해 보았다.
<div className="tweetForm__filter">필터
<select defaultValue='all' name="select" onChange={event => setSelected(event.target.value)}>
<option value="all">ALL</option>
{props.dummyTweets.reduce((acc, val) => {
if (!acc.includes(val.username)) {
acc.push(val.username);
}
return acc;}, []).map((elem, index) => <option key={index} value={elem}>{elem}</option>)}
</select>
</div>
// tweets ul에 기본으로 필터링하는 로직을 selected 상태와 함께 삽입했다.
// 필터가 없으면 항상 모든 트윗을 보여준다.
<ul className="tweets">
{props.dummyTweets.filter(elem => selected === 'all' ? true : elem.username === selected).map((elem) => <Tweet key={elem.id} tweet={elem} />)}
</ul>
트윗 삭제하는 기능, filter 활용하니 깔끔하게 구현됨
<div className="Btn-Wrapper">
<button className="tweetForm__submitButton" onClick=
{event => setTweetData(dummyTweets.filter(elem => elem.id !== tweet.id))}>
트윗 삭제
</button>
</div>