목차
1. props 다시 정리
2. props 기본값 설정 : defaultProps
3. 태그 사이의 내용을 보여주는 children
4. 비구조화 할당 문법을 통한 props 내부 값 추출
5. proTypes를 통한 props 검증
6. state
7. this.setState에 객체 대신 함수 인자 전달-+
8. 함수컴포넌트에서 useState로 state 사용
1. props
앞에서도 말했지만 props는 properties를 줄인 표현으로 컴포넌트 속성을 설정할 때 사용하는 요소이다.
아래와 같은 구조일 경우 App Component가 부모 컴포넌트이고 MyComponent Component가 자식 컴포넌트이다.
props는 부모 컴포넌트에서 설정할 수 있다.

//App 컴포넌트 import MyComponent from "./MyComponent"; const App=()=> { return ( <div> <MyComponent name="홍길동" /> </div> ); } export default App;
//MyComponent 컴포넌트 const MyComponent=(props)=>{ return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>; } export default MyComponent;
위와 같이 부모 컴포넌트에 name 속성을 홍길동이라고 줬더니 자식 컴포넌트에 props.name 자리에 홍길동이 잘 나타나게 된다.

이런식으로 name이든 다른 속성이든 props를 다르게 주면 다른 element(다른 맛 붕어빵)이 만들어진다.


2. props 기본값 설정 : defaultProps
//App 컴포넌트 import MyComponent from "./MyComponent"; const App=()=> { return ( <div> <MyComponent /> </div> ); } export default App;
부모컴포넌트에서 속성값을 안주게 되면 아래와 같이 렌더링되는데

이렇게 props값을 안받았을 경우에 default(기본값)으로 어떤 이름이 나오게 설정할 수 있다.
그게 바로 defaultProps이다
//MyComponent 컴포넌트 const MyComponent=(props)=>{ return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>; } MyComponent.defaultProps={ name: '이름없음' } export default MyComponent;

3. 태그 사이의 내용을 보여주는 children
리액트 컴포넌트를 사용할 때 컴포넌트 태그 사이의 내용을 보여주는 props를 children이라고 한다.
//MyComponent 컴포넌트 const MyComponent=(props)=>{ return <div>안녕하세요, 제 이름은 {props.children}입니다.</div>; } export default MyComponent;
//App 컴포넌트 import MyComponent from "./MyComponent"; const App=()=> { return ( <div> <MyComponent >애기</MyComponent> </div> ); } export default App;

4. 비구조화 할당 문법을 통한 props 내부 값 추출
현재 MyComponent에서 props 값을 조회할 때마다 props.name, props.children과 같이 props라는 키워드를 앞에 붙여 주고 있는데 이러한 작업을 편하게 하기위해 비구조화 할당 문법을 사용할 수 있다.
▶구조 분해 할당
배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식이다.
그 중에서 객체 구조 분해할당의 형태는 다음과 같다
var o = {p: 42, q: true}; var {p, q} = o;
위와 같이 선언해줌으로써 p와 q를 개별변수로 사용할 수 있게 된다.
p만 호출해도 42라는 값을 가져올 수 있다.
리액트에서도 마찬가지이다.
const{name, children}=props라고 해줌으로써
props.name, props.children이라고 명시를 하지 않고 그냥 name, children이라고만 해줘도 해당 값에 접근이 가능해진 것이다.
//MyComponent 컴포넌트 const MyComponent=(props)=>{ const{name, children}=props; return <div>안녕하세요, 제 이름은 {name}이자 {children}입니다.</div>; } export default MyComponent;
또는
//MyComponent 컴포넌트 const MyComponent=({name, children})=>{ return <div>안녕하세요, 제 이름은 {name}이자 {children}입니다.</div>; } export default MyComponent;
//App 컴포넌트 import MyComponent from "./MyComponent"; const App=()=> { return ( <div> <MyComponent name="길동">애기</MyComponent> </div> ); } export default App;
5. proTypes를 통한 props 검증
컴포넌트의 필수 props를 지정하거나 props의 타입(type)을 지정할 때는 proTypes를 사용한다.
proTypes를 사용하려면 코드 상단에 import 구문을 사용하여 불러와야 한다.
import ProTypes from 'prop-types';
아래와 같이 name 속성을 proTypes로 string으로 지정해놓으면 문자열이 아닌 다른 자료형일 경우 Console창에 에러메시지가 뜬다.
//MyComponent 컴포넌트 import ProTypes from 'prop-types'; const MyComponent=(props)=>{ const{name, children}=props; return <div>안녕하세요, 제 이름은 {name}이자 {children}입니다.</div>; } MyComponent.proTypes={ name:ProTypes.string } export default MyComponent;
▶isRequired를 사용하여 필수 proTypes 설정
필수로 입력돼야 하는 proType에 isRequired를 붙여준다.
//MyComponent 컴포넌트 import ProTypes from 'prop-types'; const MyComponent=(props)=>{ const{name, children}=props; return <div>안녕하세요, 제 이름은 {name}이자 {children}입니다.</div>; } MyComponent.proTypes={ name:ProTypes.string.isrequired } export default MyComponent;
▶클래스형 컴포넌트에서 props 사용
클래스형 컴포넌트에서 props를 사용할 때 render 함수에서 this.props를 조회하면 되며 defaultProps와 propTypes는 똑같은 방식으로 설정가능하다.
//MyComponent 컴포넌트 import {Component} from 'react'; import ProTypes from 'prop-types'; class MyComponent extends Component{ render(){ const {name, children}=this.props; return(<div>안녕하세요, 제 이름은 {name}이자 {children}입니다.</div>)}; } MyComponent.proTypes={ name:ProTypes.string.isrequired } export default MyComponent;
6. state
state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미한다.
props는 부모 컴포넌트가 설정하는 값이며 컴포넌트 자신을 해당 props를 읽기 전용으로만 사용할 수 있고 props를 변경하려면 부모 컴포넌트에서 바꿔줘야하지만 state는 내부에서 바뀌게 만들 수 있는 것이다.
바뀔수 있는 state 초기값을 설정해주는 형태는 아래와 같다.
컴포넌트의 state는 객체 형식이어야 한다.
초기값을 설정해주는 방법은 constructor에 설정해주거나 constructor을 사용하지 않고 바로 state를 설정해주는 방법 2가지가 있다.
this.state = { number: 0, };
클래스형 컴포넌트에서 constructor를 작성할 때는 반드시 super(props)를 호출해 주어야 하며
이 함수가 호출되면 현재 클래스형 컴포넌트가 상속받고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출해준다.
아래에 나오는 onClick이라는 이벤트는 클릭하면 onClick 다음에 오는 함수를 실행하라는 의미이며 이 함수를 넣어줄 때는 화살표 함수 문법을 사용하여 넣어줘야 한다.
함수 내부에서 this.setState라는 함수를 사용하는데 이 함수가 state 값을 바꿀 수 있게 해 준다.
//생성자에서 state 초기값 설정
import { Component } from 'react'; class Counter extends Component { constructor(props) { super(props); this.state = { number: 0, }; } render() { const { number } = this.state; return ( <div> <h1>{number}</h1> <button onClick={() => { this.setState({ number: number + 1 }); }} > +1 </button> </div> ); } } export default Counter;
//생성자 없이 state 초기값 설정
import { Component } from 'react'; class Counter extends Component { state = { number: 0, }; render() { const { number } = this.state; return ( <div> <h1>{number}</h1> <button onClick={() => { this.setState({ number: number + 1 }); }} > +1 </button> </div> ); } } export default Counter;
state값에는 여러 값이 올 수 있다.
state = { number: 0, fixNumber:0 };
7. this.setState에 객체 대신 함수 인자 전달
아래 예제코드를 보면 onClick을 했을 대 setState가 2번 호출되도록 만들었다. 즉 +2씩 증가되도록 만들려고 한 것이다.
import { Component } from 'react'; class Counter extends Component { state = { number: 0, }; render() { const { number } = this.state; return ( <div> <h1>{number}</h1> <button onClick={() => { this.setState({ number: number + 1 }); this.setState({ number: this.state.number + 1 }); }} > +1 </button> </div> ); } } export default Counter;
그런데 실제 결과는 +1씩 증가되었다.
위와 같이 작성하면 this.setState를 2번 사용하는 것임에도 불구하고 1씩 더해지는데 this.setState를 사용한다고 해서 stae 값이 바로 바뀌는 것이 아니기 때문이다.

이런 문제점을 해결하기 위해서는 this.setState를 사용할 때 객체 대신 함수를 인자로 넣어주면 된다.
위 코드를 아래코드처럼 바꿔주면 된다.
import { Component } from 'react'; class Counter extends Component { state = { number: 0, }; render() { const { number } = this.state; return ( <div> <h1>{number}</h1> <button onClick={() => { this.setState({ number: number + 1 }); this.setState(prevState=>{return {number:prevState.number+1}}); }} > +1 </button> </div> ); } } export default Counter;
함수형태로 표현하는 방식은 2개가 있다.
prevState는 기존 상태를 의미하며 기존 상태의 number에 1을 더해주는 것이다.
이렇게 함수를 사용하면 즉시 반영이 돼서 위에 있는 코드는 +2씩 잘 증가되는 것을 볼 수 있다.
//1번째 방식 this.setState(prevState=>{return {number:prevState.number+1}} //2번째 방식 this.setState(prevState=>({number:prevState.number+1}));
2번째 방식은 return을 쓰지 않고 바로 객체를 반환하는 것인데 이 방식을 쓰기 위해서는
function A(){}이런 형태일때 A()뒤에 나오는 중괄호(코드블럭)을 생략하고 써주며
객체를 반환하는 형태이므로 ( { } ) 객체를 나타내는 중괄호를 괄호로 감싸는 형태가 된다.

setState 작업이 끝난 후 또 다른 작업을 하고싶을 대는 setState의 두 번째 파라미터로 콜백함수를 등록하면 된다.
import { Component } from 'react'; class Counter extends Component { state = { number: 0, }; render() { const { number } = this.state; return ( <div> <h1>{number}</h1> <button onClick={() => { this.setState({ number: number + 1 },()=>{console.log("안녕")}); }} > +1 </button> </div> ); } } export default Counter;

8. 함수컴포넌트에서 useState로 state 사용
과거에는 함수컴포넌트에서 state를 사용할 수 없었지만 지금은 useState라는 함수를 사용해 함수 컴포넌트에서도 state를 사용할 수 있다.
userState를 알아보기 전에 배열 비구조화 할당에 대해 먼저 알아본다.
▶배열 비구조화 할당
구조 분해 할당은 구문은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식이다.
아래와 같이 red, yellow, green이라는 개별 변수로 배열 값을 접근할 수 있는 것이다.

▶useState사용
아래의 형태는 state 초기값을 ''으로 넣어준 것이다.
배열 첫번째 원소인 message는 현재 상태를 나타내고
배열 두번째 원소인 setMessage는 상태를 바꿔주는 함수를 나타내며 세터함수라고 부른다.
const [message,setMessage]=useState('');
import {useState} from 'react'; const Say=()=>{ const [message,setMessage]=useState(''); //state값을 ''으로 초기화 const onClickEnter=()=>setMessage('안녕하세요!'); //state 값을 안녕하세요로 변경 const onClickLeave=()=>setMessage('안녕히 가세요!'); return (<div> <button onClick={onClickEnter}>입장</button> {/*클릭하면 onClickEnter함수 호출*/} <button onClick={onClickLeave}>퇴장</button> <h1>{message}</h1> </div>); } export default Say;
▶useState여러번 사용
useState는 한 컴포넌트에 여러번 사용해도 상관없다.
다만 style을 usestate로 지정할 때는 배열의 첫번째 원소인 현재 상태를 CSS에 사용되는 키워드로 사용해야 하며 원래 CSS에서 font-size였던 것이 리액트 에서는 fontSize라고 표현해줘야한다. (카멜 표기+ -기호 제거)
import {useState} from 'react'; const Say=()=>{ const [message,setMessage]=useState(''); const onClickEnter=()=>setMessage('안녕하세요!'); const onClickLeave=()=>setMessage('안녕히 가세요!'); const [color,setColor]=useState('black'); const [fontSize,setfontsize]=useState(''); return (<div> <button onClick={onClickEnter}>입장</button> <button onClick={onClickLeave}>퇴장</button> <h1 style={{color,fontSize}}>{message}</h1> <button style={{color:'red'}} onClick={()=>setColor('red')}>빨간색</button> <button style={{color:'green'}} onClick={()=>setColor('green')}>초록색</button> <button style={{color:'blue'}} onClick={()=>setColor('blue')}>파란색</button> <button onClick={()=>setfontsize('50px')}>폰트증가</button> <button onClick={()=>setfontsize('20px')}>폰트감소</button> </div>); } export default Say;
props를 사용한다고 해서 값이 무조건 고정적이지는 않다. 부모 컴포넌트의 staste를 자식 컴포넌트의 props로 전달하고, 자식 컴포넌트에서 특정 이벤트가 발생할 때 부모 컴포넌트의 메서드를 호출하며 props도 유동적으로 사용할 수 있다.
출처
리액트를 다루는 기술- 김민준
'React' 카테고리의 다른 글
리액트로 영화 평점 웹서비스 만들기(클론코딩) 3탄 (0) | 2023.06.08 |
---|---|
리액트로 영화 평점 웹서비스 만들기(클론코딩) 2탄 (0) | 2023.06.07 |
리액트로 영화 평점 웹서비스 만들기(클론코딩) 1탄 (0) | 2023.06.05 |
8. 리액트 입문-Props가 뭐고 Component는 뭘까 (0) | 2023.06.04 |
7. 리액트 입문-Elements가 뭘까 (0) | 2023.06.03 |