본문 바로가기
Front-End, CS 스터디/[도서] 리액트를 다루는 기술

[도서] 리액트를 다루는 기술 #컴포넌트

by 제니운 2022. 11. 13.
728x90

 

 

 

3.1 클래스형 컴포넌트

 

- 클래스형 컴포넌트와 함수 컴포넌트의 차이점은 클래스형 컴포넌트의 경우 state 기능 및 라이프 사이클 기능을 사용할 수 있다는 것과 임의 메서드를 정의할 수 있다는 것이다.

- 함수 컴포넌트의 장점은 클래스형 컴포넌트보다 선언하기가 훨씬 편하다.

- 또한, 메모리 자원도 클래스형 컴포넌트보다 덜 사용하며, 프로젝트를 완성하여 빌드한 후 배포할 때도 함수 컴포넌트를 사용하는 것이 결과물의 파일 크기가 더 작다.

- 함수 컴포넌트의 주요 단점은 state와 라이프사이클 API의 사용이 불가능하다는 점이었으나, 리액트 v16.8 업데이트 이후 Hooks라는 기능이 도입되면서 해결되었다.

 

 

3.3 props

 

- props는 properties를 줄인 표현으로 컴포넌트 속성을 설정할 때 사용하는 요소이다.

- props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정할 수 있다.

 

 

1️⃣ props 기본값 설정 : defaultProps

 

- defaultProps는 props 값을 따로 지정하지 않았을 때 보여 줄 기본값을 설정하는 것을 말한다.

 

const MyComponent = props => {
	return <div>안녕하세요, 제 이름은 {props.name}입니다.</div>
}

MyComponent.defaultProps = {
	name = "기본 이름"
};

 

 

2️⃣ 태그 사이의 내용을 보여 주는 children

 

- 리액트 컴포넌트를 사용할 때 컴포넌트 태그 사이의 내용을 보여 주는 props인 children이 있다.

 

 

import MyComponent from "./MyComponent";

const App = () => {
	return <MyComponent>리액트</MyComponent>
}

export default App;

 

 

const MyComponent = props => {
	return (
    	<div>
        	안녕하세요, 제 이름은 {props.name}입니다.<br/>
            children 값은 {props.children}입니다.
        </div>
    )
}

 

 

3️⃣ 비구조화 할당 문법을 통해 props 내부 값 추출하기

 

- props 값을 조회할 때마다 props.name, props.children 과 같이 props라는 키워드를 앞에 붙여 준다.

- 더 편하게 하기 위해 ES6의 비구조화 할당 문법을 사용하여 내부 값을 바로 추출하는 방법을 사용한다.

 

 

const MyComponent = props => {
	const {name, children} = props;
    return(
    	<div>
        	안녕하세요, 제 이름은 {name} 입니다.<br/>
            childen 값은 {children}입니다.
        </div>
    )
}

 

 

- 객체에서 값을 추출하는 문법을 비구조화 할당이라고 부르며 구조 분해 문법이라고도 불린다.

- 함수의 파라미터 부분에서도 사용할 수 있다. 함수의 파라미터가 객체라면 그 값을 바로 비구조화해서 사용한다.

 

 

const MyComponet = ({name, children}) => {
	return(
    	<div>
        	안녕하세요, 제 이름은 {name}입니다.<br/>
            children 값은 {children}입니다.
        </div>
    )
}

 

 

4️⃣ propTypes를 통한 props 검증

 

- 컴포넌트의 필수 props를 지정하거나 props의 타입을 지정할 때는 propTypes를 사용한다.

 

 

import PropTypes from "prop-types";

(...)

MyComponent.propTypes = {
	name: PropTypes.string
}

 

 

👌 isRequired를 사용하여 필수 propTypes 설정

 

- propTypes를 지정하지 않았을 때 경고 메시지를 띄워 주는 작업, propTypes를 지정할 때 뒤에 isRequired를 붙여 주면 된다.

 

 

MyCompoent.propTypes = {
	name: PropTypes.string,
    favoriteNumber: PropTypes.number.isRequired
}

 

 

👌 더 많은 PropTypes 종

 

- array: 배열

- arrayOf(다른 propType): 특정 PropType으로 이루어진 배열, arrayOf(PropType.number)는 숫자로 이루어진 배열

- bool: true 혹은 false

- func: 함수

- number: 숫자

- object: 객체

- string: 문자열

- symbol: ES6의 Symbol

- node: 렌더링할 수 있는 모든 것(숫자, 문자열 혹은 JSX모드, children도 node PropType)

- instanceOf(클래스): 특정 클래스의 인스턴스(ex. instanceOf(MyClass))

- oneOf(["dog", "cat"]): 주어진 배열 요소 중 값 하나

- oneOfType([React.PropTypes.string, PropTypes.number]): 주어진 배열 안의 종류 중 하나

- objectOf(React.PropTypes.number): 객체의 모든 키 값이 인자로 주어진 PropType인 객체

- shape({ name: PropTypes.string, num: PropTypes.number }): 주어진 스키마를 가진 객체

- any: 아무 종류

 

 

 

5️⃣ 클래스형 컴포넌트에서 props 사용하기

 

- 클래스형 컴포넌트에서 props를 사용할 때는 render 함수에서 this.props를 조회하면 된다.

 

const { name, favoriteNumber, children } = this.props // 비구조화 할당

 

 

- 클래스형 컴포넌트에서 defaultProps와 propTypes를 설정할 때 class 내부에서 지정하는 방법도 있다.

 

 

3.4 state

 

- 리액트에서 state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미한다.

- props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이며, 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용할 수 있다.

- props를 바꾸려면 부모 컴포넌트에서 바꾸어 주어야 한다.

 

 

1️⃣ 클래스형 컴포넌트의 state

 

constructor(props){
	super(props);
    // state의 초깃값 설정하기
    this.state = {
    	number: 0
    }
}

 

 

- 클래스형 컴포넌트에서 constructor를 작성할 때는 반드시 super(props)를 호출해 주어야 한다.

- 이 함수가 호출되면 현재 클래스형 컴포넌트가 상속받고 있는 리액트의 Componet 클래스가 지닌 생성자 함수를 호출해 준다.

- this.state 값에 초깃값을 설정해 준다. 컴포넌트의 state는 객체 형식이어야 한다.

 

 

render(){
	const { number } = this.state // state를 조회할 때는 this.state로 조회한다.
	return(
    	<div>
        	<h1>{number}</h1>
            <button>
            	//onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정한다.
                onClick={() => {
                	// this.setState를 사용하여 state에 새로운 값을 넣을 수 있다.
                    this.setState({number: number + 1});
                }}
                +1
            </button>
        </div>
    )
}

 

 

👌 state를 constructor에서 꺼내기

 

class Counter extends Component {
	state = {
    	number: 0,
        fixedNumber: 0
    }
    render(){
    	const {number, fixedNumber} = this.state // state를 조회할 때는 this.state로 조회한다.
        return (...);
    }
}

 

- 위처럼 사용할 경우 constructor 메서드를 선언하지 않고도 state 초깃값을 설정할 수 있다.

 

 

👌 this.setState에 객체 대신 함수 인자 전달하기

 

this.setState((prevState, props) => {
	return {
    	// 업데이트하고 싶은 내용
    }
})

 

 

- prevState는 기존 상태이고 props는 현재 지니고 있는 props를 가리킨다.

- 업데이트 하는 과정에서 props가 필요하지 않다면 생략해도 된다.

 

 

<button>
	onClick={() => {
    	this.setState(prevState => {
        	return {
            	number: prevState.number + 1
            }
        })
        // 위 코드와 아래 코드는 똑같은 기능을 한다.
        // this.setState(prevState => ({
        	number: prevState.number + 1
        }))
    }}
</button>

 

 

👌 this.setState가 끝난 후 특정 작업 실행하기

 

- setState를 사용하여 값을 업데이트하고 난 다음에 특정 작업을 하고 싶을 때는 setState의 두 번째 파라미터로 콜백 함수를 등록하여 작업을 처리할 수 있다.

 

 

<button>
	onClick={() => {
    	this.setState(
        {
        	number: number + 1
        }, () => {
        	console.log("setState 호출")
        }
        )
    }}
    +1
</button>

 

 

2️⃣ 함수 컴포넌트에서 useState 사용하기

 

👌 배열 비구조화 할당

 

- 배열 안에 들어 있는 값을 쉽게 추출할 수 있도록 해 주는 문법이다.

 

const array = [1, 2];
const [one, two] = array;

 

 

👌 useState 사용하기

 

- 클래스형 컴포넌트에서의 state 초기값을 객체 형태를 넣어 주어야 한다.

- useState에서는 반드시 객체가 아니어도 상관없으며 값의 형태는 자유이다.

- 함수를 호출하면 배열이 반환되는데, 배열의 첫 번째 원소는 현재 상태이고 두 번째 원소는 상태를 바꾸어 주는 함수이다. 이 함수를 세터 함수라고부른다.

 

 

3.5 state를 사용할 때 주의 사항

 

 

- state 값을 바꾸어야 할 때는 setState 혹은 useState를 통해 전달받은 세터 함수를 사용해야 한다.

- 배열이나 객체를 업데이트해야 할 때는 배열이나 객체 사본을 만들고 그 사본에 값을 업데이트한 후, 그 사본의 상태를 setState 혹은 세터 함수를 통해 업데이트해야 한다.

 

 

// 객체 다루기
const object = { a: 1, b: 2, c: 3}
const nextObject = {...object, b: 2}; // 사본을 만들어서 b 값만 덮어 쓰기

// 배열 다루기
const array = [
	{ id: 1, value: true},
    { id: 2, value: true},
    { id: 3, value: false}
]

let nextArray = array.concat({ id: 4}) // 새 항목 추가
nextArray.filter(item => item.id !== 2); // id가 2인 항목 제거
// id가 1인 항목의 value를 false로 설정
nextArray.map(item => (item.id === 1 ? { ...item, value: false} : item));

 

 

- 객체에 대한 사본을 만들 때는 spread 연산자라 불리는 ...을 사용하여 처리하고 배열에 대한 사본을 만들 때는 배열의 내장 함수들을 활용한다.

 

 

 

#출처 : 리액트를 다루는 기술(저자 : 김민준 VELOPERT)

728x90