목차
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 |