Props
: props는 React 컴포넌트에 전달되는 인수이다.
- props는 태그의 속성을 통해 컴포넌트에 전달된다.
- props는 읽기 전용이다.
function PropTest(props) {
console.log(props);
return <h1>{props.name}님 반갑습니다!</h1>;
}
export default PropTest;
-----------------------------------------------
import "./App.css";
import PropTest from "./PropTest";
function App() {
return <PropTest name="suhyeon" age="28" />;
}
export default App;
console창에 props객체를 찍었을 때, name, age 프로퍼티가 있는 객체가 출력되는 것을 확인할 수 있다.
- props객체에는 부모 컴포넌트에서 전달한 인자가 객체의 프로터티 키와 값으로 묶여 객체로 전달되는 것이다.(개인적인 이해)
- 부모 컴포넌트에서 전달하는 인자는 객체 및 배열타입의 값도 전달이 가능하다. 아래 예시를 보자.
function PropTest(props) {
console.log(props);
console.log("props.userInfo", props.userInfo[0]);
return <h1>{props.userInfo[0]["name"]}님 반갑습니다!</h1>;
}
export default PropTest;
--------------------------------------------
import "./App.css";
import PropTest from "./PropTest";
function App() {
return <PropTest userInfo={[{ name: "suhyeon", age: "28" }]} />;
}
export default App;
React 엘리먼트에서 이벤트를 처리하는 방식은 기존 DOM 엘리먼트에서 이벤트를 처리하는 방식과 매우 유사하다. 몇 가지 문법 차이는 다음과 같다.
- React의 이벤트는 소문자 대신 camelCase를 사용한다.
- JSX를 사용하여 문자열이 아닌 함수로 이벤트 핸들러를 전달한다.
- React에서 지원하는 이벤트 api목록은 https://ko.reactjs.org/docs/events.html에서 필요할 때 찾아서 사용하면 될 것 같다.
// HTML 방식 <button onclick="activateLasers()"> Activate Lasers </button> ---------------------------------- // React 방식 <button onClick={activateLasers}> Activate Lasers </button>
state
는props
와 마찬가지로 일반 javascript 객체이다. 두 객체 모두 렌더링 결과물에 영향을 주는 정보를 갖고 있는데, 한 가지 중요한 방식에서 차이가 있다.
props
는 마치 함수 매개변수처럼 컴포넌트에 전달되는 반면state
는 함수 내에 선언된 변수처럼 컴포넌트 안에서 관리된다.
Returns a stateful value, and a function to update it.
- 위 사진을 보면 useState()를 호출하면 반환되는 값이 [S, setStatckAction<S>]이 반환되는 것을 확인할 수 있다.
=> 첫 번째 원소인 S는 현재 상태값을 나타내고, 두 번째 원소인 setStackAction<S>는 상태를 설정하는 메서드를 나타낸다.- 그래서 보통 사용할 때
let [name, setName] = useState("suhyeon");
처럼 사용한다.
=> useState()안에 있는 "suhyeon"은 name(=state)의 초기값이다.- 다음 예제 코드를 보며 이해해보자.
import { useState } from "react";
import "./App.css";
import PropTest from "./PropTest";
function App() {
let [myName, setMyName] = useState("suhyeon");
return <PropTest userInfo={[{ name: myName, age: "28" }]} />;
}
export default App;
------------------------------------
function PropTest(props) {
console.log(props);
console.log("props.userInfo", props.userInfo[0]);
return <h1>{props.userInfo[0]["name"]}님 반갑습니다!</h1>;
}
export default PropTest;
위 코드에서
let [myName, setMyName] = useState("suhyeon");
로 상태의 초기값을 "suhyeon"으로 설정하고, myName이라는 상태값을 PropTest 컴포넌트의 props로 넘겨주었는데 문제없이 나오는 것을 볼 수 있다.
- 다음은 버튼을 한 개 만들어서 버튼을 클릭하면 색이 변하도록 만들어보자.
import { useState } from "react";
import "./App.css";
import PropTest from "./PropTest";
function App() {
let [myName, setMyName] = useState("suhyeon");
let [textColor, setTextColor] = useState("red");
const changeColor = () => {
textColor === "red" ? setTextColor("blue") : setTextColor("red");
};
return (
<>
<PropTest userInfo={[{ name: myName, age: "28" }]} color={textColor} />
<button onClick={changeColor}>Change Color</button>
</>
);
}
export default App;
------------------------------------------------------
function PropTest(props) {
console.log(props);
console.log("props.userInfo", props.userInfo[0]);
return (
<h1 style={{ color: props.color }}>
{props.userInfo[0]["name"]}님 반갑습니다!
</h1>
);
}
export default PropTest;
- 위 코드를 보면 button 태그에 onClick이벤트를 부여해서 클릭할 때
textColor === "red" ? setTextColor("blue") : setTextColor("red");
삼항 연산자를 사용해서 현자 textColor 상태값이 red이면 blue로 red가 아니면 red로 상태값을 업데이트 해주도록 작성했다.- App컴포넌트의 상태값이 PropTest컴포넌트의 props로 전달되어 사용되는 것을 확인할 수 있다.
그렇다면 PropTest컴포넌트에서 App컴포넌트의 상태값을 변경할 수 없는지 알아보자.
import { useState } from "react";
import "./App.css";
import PropTest from "./PropTest";
function App() {
let [myName, setMyName] = useState("suhyeon");
let [textColor, setTextColor] = useState("green");
const changeColor = (color) => {
textColor === "green" ? setTextColor(color) : setTextColor("green");
};
return (
<>
<PropTest
userInfo={[{ name: myName, age: "28" }]}
color={textColor}
clickEvent={changeColor}
/>
</>
);
}
export default App;
--------------------------------------------------
function PropTest(props) {
console.log(props);
console.log("props.userInfo", props.userInfo[0]);
return (
<>
<h1 style={{ color: props.color }}>
{props.userInfo[0]["name"]}님 반갑습니다!
</h1>
<button onClick={() => props.clickEvent("yellow")}>Change Color</button>
</>
);
}
export default PropTest;
- 위 코드를 작성하면서 부모 컴포넌트에서 자식 컴포넌트로 state를 변경하는 함수를 props로 보내준다는 것 까지 생각을 하는건 어렵지 않았다.
- 그런데 PropsTest컴포넌트에서 button 태그의 onClick 이벤트에
<button onClick={props.clickEvent("yellow")}>Change Color</button>
로 코드를 작성하면 아래의 영상같이 계속 리렌더링되는 현상이 발생했다.=> 콘솔창에는 다음과 같은 에러코드가 출력됐다.
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate.
=> 여기서Maximum update depth exceeded.
발생하는 이유는 단순히 함수를props.clickEvent("yellow")
로 호출하는 것은 다음과 같은 루틴이 생긴다
=> (함수를 부른다 => render를 다시한다 => 또 함수를 부른다)가 반복되는 것이다.
=> 여기서 함수를 부른다는 것은 jsx문법인 {}안에 함수명()로 썼기때문에 바로 호출의 의미가 되는 것이다.
=> 그렇기때문에() => this._toggleState(param)
로 작성해야 반복이 발생하지 않는다.
=> 만약 매개변수가 없는 함수같은 경우는onClick={함수명}
처럼 ()를 빼고 적어주면 된다.
공식문서에 어떤게
state
가 되어야 하는지 살펴보는 부분이 있는데, 나름 이해가 잘 되는 것 같아서 블로그에도 작성을 하려고 한다...
- 부모 컴포넌트로부터 props를 통해 전달이 되나요? 그러면 state가 아니다.
- 시간이 지나도 변하지 않나요? 그러면 state가 아니다.
- 컴포넌트 안의 다른 state나 props를 갖고 계산이 가능한가?? 그러면 state가 아니다.
앞으로 연습할 때 위 3가지를 염두해두고 state를 설정하는 연습을 해야겠다..