오늘 내용을 아래 그림 하나로 요약할 수 있겠다.
💻 출처 : https://ooeunz.tistory.com/135
import React from "react";
import Hello from "./Hello";
function App() {
return <Hello name="기운찬곰" color="blue" />;
}
export default App;
import React from "react";
function Hello({ name, color }) {
return <div style={{ color }}>{name}</div>;
}
export default Hello;
부모 컴포넌트인 App에서 자식 컴포넌트인 Hello를 호출 할 수 있다.
그리고 부모에서 자식에게 값을 넘겨줄 수 있는데 자식컴포넌트는 이를 props 형태로 받아오게 된다. 원래 정석대로 하면 props를 받고 props.name
, props.color
로 써야 하는데 일반적으로 비구조할당을 통해 바로 변수로 받는 것을 선호한다.
이번엔 부모에서 name 값을 넘겨주지 않는다면 어떻게 될까? 🤔 에러는 나지 않지만 undefined 값을 가지게 된다. 만약 name 값을 넘기지 않았을 때 기본 값(default)으로 대체하고 싶다면 defaultProps를 사용하면 된다.
// App.js
function App() {
return <Hello color="blue" />; // name props를 넘겨지 않음
}
// Hello.js
import React from "react";
function Hello({ name, color }) {
console.log(name); // name이 undefined일 때 default 값이 대신 들어감
return <div style={{ color }}>{name}</div>;
}
Hello.defaultProps = {
name: "이름없음", // default 값 설정
};
export default Hello;
태그 사이에다가도 값을 넘겨줄 수 있다. 이 경우는 보통 HTML 태그를 넘겨줄 때 많이 쓰인다. 자식은 태그 사이 값을 받을때 children
을 통해 받을 수 있다.
// App.js
function App() {
return (
<Hello color="blue">
<p>태그 사이 값을 통째로 넘겨주는건 children</p>
</Hello>
);
}
// Hello.js
function Hello({ name, color, children }) { // ✅
return (
<>
<div style={{ color }}>{name}</div>
{children}
</>
);
}
리액트에서는 컴포넌트 내부에 바뀔 수 있는 값이 있다면 state를 사용해야 한다. 그래야 리액트가 상태변화를 알아차리고 리렌더링 해주기 때문이다.
간단하게 카운트를 만들어서 state 관리에 대해 알아보는 실습을 해보겠다.
// Counter.js
import React, { useState } from "react";
function Counter() {
const [number, setNumber] = useState(0);
const onIncrease = () => {
setNumber(number + 1);
};
const onDecrease = () => {
setNumber(number - 1);
};
return (
<>
<h1>{number}</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</>
);
}
export default Counter;
여기서는 함수형 컴포넌트에서의 useState를 사용했다.
import React, { useState } from "react";
function InputForm() {
const [inputs, setInputs] = useState({
name: "",
email: "",
});
const { name, email } = inputs;
const onChange = (e) => {
const { name, value } = e.target;
setInputs({
...inputs,
[name]: value,
});
};
const onReset = () => {
setInputs({
name: "",
email: "",
});
};
return (
<div>
<input name="name" placeholder="이름" onChange={onChange} value={name} />
<input
name="email"
placeholder="이메일"
onChange={onChange}
value={email}
/>
<button onClick={onReset}>초기화</button>
<hr />
<div>
<b>값: </b>
{name} ({email})
</div>
</div>
);
}
export default InputForm;
아까보다는 조금 복잡하고 관리해야할 상태도 많아졌다.
리액트에서 객체를 업데이트하기 전에 지켜줘야할 규칙이 있다. 바로 불변성 유지. 즉, 기존 객체를 수정하면 안되고 새로운 객체를 넣어줘야 한다. 그래야 리액트가 상태변화를 감지해서 변화된 부분을 리렌더링 할 수 있기 때문이다.
불변성을 유지하기 위한 방법으로는 여러가지가 있을 수 있는데 아래는 대표적인 2가지 방법을 소개한다.