state
props
내가 좋아하는 웹사이트에서 데이터거 state/props 중 어떤 걸로 관리가 되어야 하는지 체크해보는 것도 좋다.
해당 컴포넌트의 속성이다.
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
<Child name={"suri"} text={"I'm the eldest child"} />
// 그냥 문자열인 경우 중괄호를 생략해도 된다.
<Child>You can do it!</Child>
</div>
);
}
function Child(props) {
console.log("props : ", props);
return (
<div className="child">
<h1>{props.name}</h1>
<p>{props.text}</p>
<p>{props.children}></p>
</div>
);
}
export default Parent;
const App = () => {
const itemOne = "React를";
const itemTwo = "배우고 있습니다.";
return (
<div className="App">
<Learn text={itemOne + ' ' + itemTwo}/>
</div>
);
};
const Learn = (props) => {
console.log(props)
return <div className="Learn">{props.text}</div>;
};
export default App;
const props = {
name: "walli"
};
return <Hello {...props} />;
const obj = {
name : "suri",
age : 20,
};
return <Hello test={obj} />;
const Hello (props) => {
return <div>{props.test.name}</div>
}
애플리케이션의 상태이다.
리액트에서 state를 다루는 방법 중 하나로 제공하는 특별한 함수이다. 이를 통해, 함수 컴포넌트도 state 를 다룰 수 있게 되었다.
리액트로부터 useState를 불러온다. import { useState } from "react";
컴포넌트 안에서 useState를 호출한다.
const [isChcked, setIsChecked] = useState(false)
// useState의 리턴값을 구조 분해 할당한 변수이다.
// const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);
===비교===
const stateHookArray = useState(false);
const isChecked = stateHookArray[0];
const setIsChecked = stateHookArray[1];
<span>{isChecked ? "Checked" : "unChecked"}</span>
function CheckboxExample() {
const [isChecked, setIsChecked] = useState(false);
const handleChecked = (event) => {
setIsChecked(event.target.checked); // 이벤트 객체에 변경된 checked 값을 불러와 넣어준다?
};
return (
<div className="App">
<input type="checkbox" checked={isChecked} onChange={handleChecked} />
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
</div>
);
}
리렌더링
된다. 즉, 화면이 업데이트 된다.
function ExampleWithManyStates() {
// 여러 개의 state를 선언할 수 있습니다!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
<button onclick="eventHandler()">Event</button>
===비교===
<button onClick="eventHandler">Event</button>
<button onClick={() => handleClick("나는 개발자이다.")}>Click ME!</button>
폼 엘리먼트(input
textarea
select
)는 사용자의 입력값을 받는다. 리액트에서는 이러한 변경될 수 있는 입력값을 컴포넌트의 state로 관리하고 업데이트한다.
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>
)
};
버튼이나 a 태그를 통한 링크 이동 등에 자주 사용되는 이벤트이다.
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
};
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
<h1>{name}</h1>
<button onClick={() => alert(name)}>Click Me!?</button>
// alert 창을 띄우는 버튼을 추가했다.
</div>
);
}
onClick={alert(name)}
이렇게 해주면 안 된다!흠, 정리하면 이런 내용인 것 같다.
이벤트가 발생하면 이벤트 핸들러를 호출하고 그 안에서 변수 갱신 함수를 호출하면, 인자로 변화된 이벤트 객체의 값을 가져와서 state 저장 변수에 넣어준다. state 저장 변수의 값은 이벤트+이벤트핸들러에 의해 계속 바뀔 수 있는 값이다.
<Select>
사용자가 drop down 목록을 열어 한 가지 옵션을 선택하면, state 변수에 갱신이 된다.
function SelectExample() {
const [choice, setChoice] = useState("som");
const members = ["som", "ming", "viho", "yoojin", "tanso"];
const options = members.map((member) => {
return <option value={member}>{member}</option>;
});
const handler = (event) => {
setChoice(event.target.value)
};
return (
<div className="App">
<select onChange={handler}>{options}</select>
<h3>You choose "{choice}"</h3>
</div>
);
}
const [showPopup, setShowPopup] = useState(false);
const togglePopup = (event) => {
let isOpen = event.target.className === 'open'
isOpen ? setShowPopup(true) : setShowPopup(false)
};
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>
);
}
import "./styles.css";
import { useState } from "react";
export default function App() {
// 👇 useState 두 번 사용!
// const [name, setName] = useState("");
// const [phone, setPhone] = useState("");
// const handleNameInputChange = (e) => {
// // console.log(e.target.value)
// setName(e.target.value);
// };
// const handlePhoneInputChange = (e) => {
// // console.log(e.target.value)
// setPhone(e.target.value);
// };
// 👇 하나의 객체로 관리하기!
const [userInfo, setUserInfo] = useState({
name: "",
phone: ""
});
const handleInputChange = (e) => {
const { name, value } = e.target;
setUserInfo({
...userInfo,
[name]: value
});
};
return (
<div className="App">
<input
name="name"
placeholder={"이름을 입력해주세요"}
onChange={handleInputChange}
/>
<br />
<input
name="phone"
placeholder={"전화번호를 입력해주세요"}
onChange={handleInputChange}
/>
<br />
<button>제출</button>
<div>
<div>{`이름: ${userInfo.name}`}</div>
<div>{`휴대전화: ${userInfo.phone}`}</div>
</div>
</div>
);
}
리액트가 state를 통제할 수 있는 컴포넌트이다. input에 값 입력 시, state도 그 때 그 때 바뀌는 방식으로 통제할 수 있다. 리액트는 상태에 해당하는 데이터를 따로 관리하고 싶어한다. e.g. 트윗 전송 폼 컴포넌트
페이지를 만들기 이전에, 컴포넌트 계층 구조로 나누는 것이 가장 먼저 해야할 일이다.
데이터는 위에서 아래로 흐른다. (하향식)
리액트는 단방향 데이터 흐름
을 따른다.
어떤 데이터를 상태로 두어야 할까? 3가지 질문을 통해 답을 찾자.
상태 데이터는 최소화하는 것이 바람직하다. 그렇지 않으면 앱이 복잡해진다.
하나의 상태를 기반으로 두 컴포넌트가 영향을 받는다면, 공통 소유 컴포넌트를 찾아 그 곳에 상태를 위치시킨다.
const App = () => {
const itemOne = {name : 'suri', age : 26};
return (
<div className="App">
<Learn info={itemOne} />
</div>
);
};
const Learn = ({info}) => {
return <div className="Learn">{info.name}</div>;
};
export default App;
Q. input 태그 안에 checked나 value 속성을 꼭 넣어야 하나? 넣지 않아도 구현은 되는 것 같다.
Q. 화살표 함수에서 return이 생략되는 거 조금 헷갈린다. return을 넣어주나 빼주나 그대로 실행이 된다. 흐음.
Q. 두 가지 방법 모두 arrow function 을 사용하여 함수를 정의하여야 해당 컴포넌트가 가진 state에 함수들이 접근할 수 있습니다. 화살표 함수가 아니어도 되던데..
Q. 객체의 형태로 값을 전달하고 싶을 때? 는 어떻게 하나?
Q. select 태그 안에서 option을 입력할 때, map 메소드를 활용해서 배열로 전달해도 가능한가보다. 원래 html태그에서는 그런 건 없다.
Q. const { name, value } = e.target; 객체로 데이터 관리하기에서 e.target을 구조분해 했을 때, name과 value에 각각 무엇이 담기는지? name은 value일 테고, value는 이벤트에 의해 바뀐 값이 되어야 하지 않나..