Chapter1. React State & Props
1-1 Props
1-2 State
1-3 이벤트 처리
1-4 Controlled Component
1-5 React 데이터 흐름
React의 개발 방식의 가장 큰 특징
"페이지 단위가 아닌, 컴포넌트 단위로 시작"
- 변하지 않는 컴포넌트 외부로부터 전달받은 값.
- 부모 컴포넌트(상위 컴포넌트)로부터 전달받은 값.
- 어떤 타입의 값도 넣어 전달할 수 있는 객체의 형태
- 함부로 변경될 수 없는 읽기 전용(read-only) 객체
- 클래스 컴포넌트뿐만 아니라 함수형 컴포넌트에서도 사용할 수 있음
- props의 속성은 여러 개 지정할 수 있음.
살면서 변할 수 있는 값.
컴포넌트 내부에서 변화하는 값.
React에서는 state 를 다루는 방법 중 하나로 useState
라는 특별한 함수를 제공한다.
useState
를 불러와야 한다. import
키워드로 useState
를 불러온다. import { useState } from "react";
function CheckboxExample() {
// const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);
const [isChecked, setIsChecked] = useState(false);
}
[코드] useState 문법 예시
useState
를 호출하면 배열을 반환하는데,
배열의 0번째 요소는 현재 state 변수이고,
1번째 요소는 이 변수를 갱신할 수 있는 함수다.
useState
의 인자로 넘겨주는 값은 state의 초깃값.
이 state 변수에 저장된 값을 사용하려면 JSX 엘리먼트 안에 직접 불러서 사용하면 된다.
state를 갱신하려면 state 변수를 갱신할 수 있는 함수인 setIsChecked
를 호출한다.
input[type=checkbox]
엘리먼트의 값이 변경되면 onChange
이벤트가 발생하고, 이벤트 핸들러 함수가 작동되는 패턴은 React에서도 마찬가지.onChange
이벤트가 이벤트 핸들러 함수인 handleChecked
를 호출하고,setIsChecked
를 호출.setIsChecked
가 호출되면 호출된 결과에 따라 isChecked
변수가 갱신되며,isChecked
변수를 CheckboxExample
컴포넌트에 넘겨 해당 컴포넌트를 다시 렌더링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>
);
}
- React의 이벤트 처리(이벤트 핸들링; Event handling) 방식은 DOM의 이벤트 처리 방식과 유사
- 카멜 케이스(camelCase) 를 사용한다
- JSX를 사용하여 문자열이 아닌 함수로 이벤트 처리 함수(이벤트 핸들러; Event handler)를 전달한다
HTML에서 이벤트 처리 방식이 아래와 같다면,
<button onclick="handleEvent()">Event</button>
React의 이벤트 처리 방식은 아래와 같다.
<button onClick={handleEvent}>Event</button>
onChange
는input
의 텍스트가 바뀔 때마다 발생하는 이벤트
onChange
이벤트가 발생하면 e.target.value
를 통해 이벤트 객체에 담겨있는 input
값을 읽어올 수 있다.handleChange
함수가 작동하며, 이벤트 객체에 담긴 input
값을 setState
를 통해 새로운 state 로 갱신한다.
onClick
이벤트는 말 그대로 사용자가 클릭이라는 행동을 하였을 때 발생하는 이벤트- 버튼이나
<a>
tag 를 통한 링크 이동 등과 같이 주로 사용자의 행동에 따라 애플리케이션이 반응해야 할 때 자주 사용하는 이벤트
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
<button onClick={alert(name)}>Button</button>
<h1>{name}</h1>
</div>
);
};
위와 같이 onClick
이벤트에 alert(name) 함수를 바로 호출하면 컴포넌트가 렌더링 될 때 함수 자체가 아닌 함수 호출의 결과가 onClick
에 적용되므로 버튼을 클릭할 때가 아닌 컴 포넌트가 렌더링 될때 alert가 실행되고 onClick
에 적용되어 클릭했을 때 아무런 결과도 일어나지 않음.
--> 따라서 onClick
이벤트에 함수를 전달할 때는 함수를 호출하는 것이 아닌, 아래와 같이 리턴문 안에서 함수를 정의하거나 리턴문 외부에서 함수를 정의 후 이벤트에 함수 자체를 전달해야 한다. 단, 두 가지 모두 arrow function을 사용하여 함수를 정의해야 해당 컴포넌트가 가진 state에 함수들이 접근가능함.
// 함수 정의하기
return (
<div>
...
<button onClick={() => alert(name)}>Button</button>
...
</div>
);
};
// 함수 자체를 전달하기
const handleClick = () => {
alert(name);
};
return (
<div>
...
<button onClick={handleClick}>Button</button>
...
</div>
);
};
<select>
select tag
는 사용자가 drop down 목록을 열어 그중 한 가지 옵션을 선택하면, 선택된 옵션이 state 변수에 갱신됨
import React, { useState } from "react";
import "./styles.css";
function SelectExample() {
const [choice, setChoice] = useState("apple");
const fruits = ["apple", "orange", "pineapple", "strawberry", "grape"];
const options = fruits.map((fruit) => {
// options 컴포넌트를 변화가 일어나는 select태그에 작성. 이 options컴포넌트는 map화 되어있다.
return <option value={fruit}>{fruit}</option>;
});
console.log(choice);
const handleFruit = (event) => {
//TODO : select tag 가 정상적으로 작동하도록
setChoice(event.target.value);
// 변화가 일어나는 태그는 바로 select태그 이다. 그러므로 select태그에 onChange이벤트를 작성한다. (onChange에서는 갱신함수인 setChoice를 작성하고 거기에서 target.value 작성 )
};
return (
<div className="App">
<select onChange={handleFruit}>{options}</select>
<h3>You choose "{choice}"</h3> // h3 태그에 저장변수인 choice를 써준다.
</div>
);
}
export default SelectExample;
Pop up
Pop up 역시 Pop up 의 open 과 close 를 state 를 통해 관리할 수 있음
import React, { useState } from "react";
import "./styles.css";
function App() {
const [showPopup, setShowPopup] = useState(false);
const togglePopup = () => {
// Pop up 의 open/close 상태에 따라
// 현재 state 가 업데이트 되도록 함수를 완성하세요.
if(showPopup===false){
setShowPopup(true)
} else(setShowPopup(false))
};
return (
<div className="App">
<h1>Fix me to open Pop Up</h1>
{/* 버튼을 클릭했을 때 Pop up 의 open/close 가 작동하도록
button tag를 완성하세요. */}
<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;
input에 값 입력 시, state도 그때그때 바뀌면(onChange) 됨. 그리고 이 변경된 state와 input의 value 또한 같게 작성.
import "./styles.css";
import React, { useState } from "react";
export default function App() {
const [username, setUsername] = useState("");
const [msg, setMsg] = useState("");
return (
<div className="App">
<div>{username}</div>
<input
type="text"
value={username}
// 컨트롤 컴포넌트
onChange={(event) => setUsername(event.target.value)}
// 컨트롤 컴포넌트 //
placeholder="여기는 인풋입니다."
className="tweetForm__input--username"
></input>
<div>{msg}</div>
{/* TODO : 위 input과 같이 입력에 따라서 msg state가 변할 수 있게
아래 textarea를 변경하세요. */}
<textarea
placeholder="여기는 텍스트 영역입니다."
className="tweetForm__input--message"
// 컨트롤 컴포넌트 //
onChange={(event) => setMsg(event.target.value)}
// 컨트롤 컴포넌트 //
value={"msg"} // 안에 태그명을 넣어야 작동됨!
></textarea>
</div>
);
}
데이터는 위에서 아래로 흐른다. 즉, 데이터를 전달하는 주체는 부모 컴포넌트가 된다.
React에서 데이터를 다룰 때는 컴포넌트들 간의 상호 관계와 데이터의 역할, 데이터의 흐름을 고려하여 위치를 설정해야 함.
정리
onClick
이벤트 처리로 togglePopup
함수를 넣어onClick={togglePopup}
형태로 setShowPopup
을 호출showPopup
의 초깃값이 바꾸려면 -> setShowPopup