props
컴포넌트에 직접 주입하는 값을 props
라고 한다.
children
도 props
의 일부이다.props
로 className
이나 여러 handler
를 줄 수도 있다.컴포넌트 합성
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
컴포넌트 추출
props
기본 사용법App 컴포넌트에서 Fruit 컴포넌트를 사용할 때, 'name' 값을 전달해주고 싶다면 다음처럼 하면 된다.
const App = () => {
return (
<Fruit name="Apple" />
)
}
그리고 전달한 값을 Fruit 컴포넌트에서 사용하려면 Fruit 컴포넌트 인자로 props
를 전달해주고, props.name
으로 접근해서 name 값을 사용할 수 있다.
이때, props
는 객체 형태로 전달된다!
const Fruit = (props) => {
return (
<>
<div>{props.name}</div>
</>
)
}
👉 실행결과
props
Fruit 컴포넌트에 다른 props
(color
, emoji
)도 전달해보았다.
Fruit 컴포넌트에서 이를 받아와서 props.color
로 배경색을 지정하고, props.name
아래에 props.emoji
도 출력해보았다.
const Fruit = (props) => {
return (
<>
<div style={{backgroundColor: props.color}}>{props.name}</div>
<div>{props.emoji}</div>
</>
)
}
const App = () => {
return (
<>
<Fruit name="Apple" color="Red" emoji="🍎" />
<br/>
<Fruit name="Banana" color="Yellow" emoji="🍌" />
</>
)
}
👉 실행결과
🤔 비구조화 할당
매번 접근할 때마다props.~~~
을 입력하는 게 번거롭다면, Fruit의 인자에 비구조화 할당을 사용하여 좀 더 간결하게 작성할 수도 있다.const Fruit = ({name, color, emoji}) => { return ( <> <div style={{backgroundColor: color}}>{name}</div> <div>{emoji}</div> </> ) }
defaultProps
컴포넌트에 props
값을 지정하지 않았을 때, 기본값을 설정할 수 있다.
name
, color
, emoji
의 기본값으로 모두 ???
을 주었다.
const Fruit = (props) => {
return (
<>
<div style={{backgroundColor: props.color}}>{props.name}</div>
<div>{props.emoji}</div>
</>
)
}
Fruit.defaultProps = {
name: "???",
color: "???",
emoji: "???"
}
const App = () => {
return (
<>
<Fruit name="Apple" color="Red" emoji="🍎" />
<br />
<Fruit name="Banana" color="Yellow" emoji="🍌" />
<br />
<Fruit />
<br />
<Fruit color="Purple" emoji="🍇" />
</>
)
}
👉 실행결과
props
를 아무것도 전달하지 않은 <Fruit />
는 name, emoji 부분에 모두 '???'이 출력되고 배경색이 바뀌지 않은 것을 알 수 있다. 또한, name을 전달하지 않은 <Fruit color="Purple" emoji="🍇" />
는 name 부분에 '???'이 출력된 것을 알 수 있다.
props.children
Fruit 컴포넌트를 감싸는 Wrapper 컴포넌트를 새로 만들었다.
const Wrapper = () => {
return (
<div style={{border: "3px solid black", width: 400, height: 300}}></div>
)
}
const App = () => {
return (
<>
<Wrapper>
<Fruit name="Apple" color="Red" emoji="🍎" />
<br />
<Fruit name="Banana" color="Yellow" emoji="🍌" />
<br />
<Fruit />
<br />
<Fruit color="Purple" emoji="🍇" />
</Wrapper>
</>
)
}
👉 실행결과
실행해보면 Fruit 컴포넌트들이 화면에 출력되지 않았다.
❗ 이때, Wrapper 컴포넌트에 props
를 전달하여 props.children
을 렌더링 해주어야 한다.
const Wrapper = (props) => {
return (
<div style={{border: "3px solid black", width: 400, height: 300}}>
{props.children}
</div>
)
}
👉 실행결과
Wrapper 태그 내부에 있던 Fruit가 모두 잘 출력되었다.
State
공식 문서에 나와있는 클래스 컴포넌트로 구현된 시계 예제를 함수형 컴포넌트로 똑같이 구현할 수 있다.
클래스 컴포넌트 | 함수형 컴포넌트 |
---|---|
DidMount() | useEffect(...,[]) |
WillUnmount() | useEffect 에서 return 으로 cleanup |
this.state 로 초기화, tick() 에서 업데이트 | usetState 에서 set할 때 초기화, tick() 에서 업데이트 |
setState() | useState() |
---|---|
클래스형 컴포넌트에서 State 관리 | 함수형 컴포넌트에서 State 관리 |
setState()
사용 시 유의할 점State
를 수정 ❌, 직접 수정하면 렌더가 되지 않아서 화면에 출력되지 않는다.// ❌ Wrong
this.state.comment = 'Hello';
// ⭕ Correct
this.setState({comment: 'Hello'});
State
업데이트는 비동기적setState()
호출을 한꺼번에 처리할 수 있다. 이때 기대한 값과 다른 값이 나올 수 있는데, 이는 콜백함수를 사용하여 해결할 수 있다.// ❌ Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
// ⭕ Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
setState()
를 호출할 때 리액트는 제공한 객체를 현재 State
로 병합한다.🤔 함수형 vs 클래스
현재는 함수형 컴포넌트에 Hook이 추가되면서 클래스 컴포넌트보다 함수형 컴포넌트가 주로 사용된다.
공식문서 - React.Component
공식문서 - 생명주기 도표