React 게시글은 대부분 인프런의 '한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지' 강의를 기반으로 내용을 정리했습니다.
Props
Props는 State와 더불어 React의 대표적인 기능 중 하나이다. Props는 컴포넌트에게 데이터를 전달하는 기본적이고 효율적인 기능이다. Props는 Properties의 줄임말이다.
//import './App.css';
import MyHeader from './MyHeader';
import React from 'react';
import Counter from './Counter';
function App() {
const number = 5;
return (
<div>
<MyHeader />
<Counter initialValue={5}/> <!-- Counter 컴포넌트에 값 전달-->
</div>
);
}
export default App;
위의 코드를 보면 Counter 컴포넌트에 initialValue={5}라는 코드를 추가했다. initialValue를 추가하면 App 컴포넌트에서 Counter 컴포넌트로 값을 넘길 수 있다.
Counter 컴포넌트에서 부모로부터 받아온 값을 전달 받기 위해 매개변수를 하나 넣어준다. 그리고 console에 찍어보면 props 변수에 객체로 전달된 값을 볼 수 있다.
import React, {useState} from 'react';
const Counter = (props) =>{ // 매개변수를 이용해 전달된 값을 받는다.
console.log(props);
const [count, setCount] = useState(0);
const onIncrease = () => {
setCount(count+1);
}
const onDecrease = () => {
setCount(count-1);
}
return (
<div>
<h2>{count}</h2>
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
</div>
)
};
export default Counter;
객체로 전달되기 때문에 여러 개의 Props를 보내도 괜찮다.
<Counter a={1} initialValue={5}/>
객체에서 값을 꺼내오고 싶으면 일반적으로 사용하는 점 표기법으로 꺼내오면 된다.
const [count, setCount] = useState(props.initialValue);
Props 값이 여러 개면 하나하나 다 작성하기 힘드니 객체를 만들어 스프레드 연산자를 이용해 전달해도 된다.
function App() {
const number = 5;
const counterProps = {
a : 1,
b : 2,
c : 3,
d : 4,
e : 5,
initialValue : 5
};
return (
<div>
<MyHeader />
<Counter {...counterProps}/> <!-- 객체를 펼쳐주는 스프레드 연산자-->
</div>
);
}
export default App;
만약 값을 전달할 때 initialValue를 빼먹게 되면 어떻게 될까? 부모로부터 initialValue를 전달받지 못했는데 Counter 컴포넌트에서는 그 값을 사용할 경우 Counter 컴포넌트의 initialValue에는 undefined 상태이다. 그래서 그 상태에서 +나 -버튼을 누르면 NaN이 출력된다. 이 현상은 명백한 오류이다. 우리는 값이 넘어오지 않는 상황까지 고려하여 개발해야한다. 그럼 어떻게 해결할까? 바로 defaultProps를 이용하면 된다.
import React, {useState} from 'react';
const Counter = (props) =>{
console.log(props);
const [count, setCount] = useState(props.initialValue);
const onIncrease = () => {
setCount(count+1);
}
const onDecrease = () => {
setCount(count-1);
}
return (
<div>
<h2>{count}</h2>
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
</div>
)
};
<!--defaultProps 추가-->
Counter.defaultProps = {
initialValue : 0,
};
export default Counter;
defaultProps가 있어 부모로부터 initialValue 값이 넘어오지 않더라도 0으로 초기화되어 기존 기능을 오류 없이 그대로 이용할 수 있다.
참고로 비구조화 할당 방법을 이용하여 객체에서 값 하나만 사용하면 될 경우는 아래와 같이 작성하면된다.
const Counter = ({ initialValue }) =>{
그럼 이제 새로운 예제를 만들어보자. 부모(Counter)로부터 받아온 initialValue의 값이 짝수인지 홀수인지 판별하는 프로그램이다. 먼저 Counter에 컴포넌트를 추가하자.
return (
<div>
<h2>{count}</h2>
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
<OddEvenResult count={count} /> <!-- OddEvenResult 컴포넌트 추가, count 값 넘겨주기-->
</div>
)
그리고 OddEvenResult를 구현해보자.
const OddEvenResult = ({count}) => {
console.log(count);
return <>{count % 2 === 0 ? "짝수" : "홀수"}</>
};
export default OddEvenResult;
버튼을 누를 때마다 count의 값이 짝수인지 홀수인지 잘 출력된다. 리액트에서 컴포넌트는 부모에서 내려주는 Props의 값이 변경되면 그 밑의 자식들을 다시 호출하면서 다시 렌더(리렌더)를 하게된다.
Props는 다양한 타입을 전달할 수 있는데 컴포넌트도 전달할 수가 있다. Container.js를 만들어 화면에 딱 붙어있는 요소들을 예쁘게 만들어보자.
const Container = ({children}) => {
return <div style={{margin:20, padding: 20, border:"1px solid black"}}>
{children}
</div>
}
export default Container;
App.js에서도 수정해줘야한다.
return (
<Container> <!--Container 컴포넌트로 감싸주기-->
<div>
<MyHeader />
<Counter {...counterProps}/>
</div>
</Container>
);
그러면 설정한 CSS가 적용되어 이쁘게 나온다.