컴포넌트 선언 방식
1. 함수형 컴포넌트 << 주로 사용
2. 클래스형 컴포넌트
import React, { Component } from "react";
class App extends Component{
render() {
const name = "react";
return <div className="react">{name}</div>;
}
}
props는 컴포넌트 속성을 설정할 때 사용하는 요소이다.
props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정한다.
// MyComponent.js
import React from "react";
const MyComponent = (props) => {
return <div>안녕하세요, 제 이름은 {props.name} 입니다.</div>;
};
export default MyComponent;
App컴포넌트(부모 컴포넌트)에서 MyComponent의 props 값을 지정
//App.js
import MyComponent from "./MyComponent";
function App() {
return <MyComponent name="React" />;
}
export default App;
props 값을 따로 지정하지 않았을 때 보여 줄 기본값 설정
MyComponent.defaultProps = {
name: "기본 이름",
};
컴포넌트 태그 사이의 내용을 보여주는 props
// App.js
import MyComponent from "./MyComponent";
function App() {
return <MyComponent>리액트</MyComponent>;
}
export default App;
MyComponent 내부에서 {props.children}
값으로 보여준다.
객체에서 값을 추출하는 문법
const {name, children } = props;
함수의 파라미터 부분에서도 사용할 수 있다.
const MyComponent = ({name, children}) => { ... }
컴포넌트의 필수 props를 지정하거나 props의 타입을 지정할 때 propTypes
를 사용
import PropTypes from 'prop-types';
MyComponent.propTypes = {
name: PropTypes.string
};
name 값은 무조건 문자열 형태로 전달해야 된다는 것을 의미함
만약 name을 숫자로 전달했을 시 값이 나타나기는 하지만 콘솔에 경고 메시지를 출력한다.
propsTypes를 지정하지 않았을 때 경고 메세지를 띄워줌
MyComponent.propTypes = {
name: PropTypes.string.isRequired
};
const {name, favoriteNumber, children } = this.props;
defaultProps와 propsTypes는 똑같은 방식으로 설정할 수도 있고, 다음과 같이 class 내부에서 지정하는 방법도 있다.
class MyComponent extends Component {
static defaultProps = {
name: '기본 이름'
};
static propTypes = {
name: PropTypes.string,
favoriteNumber: PropTypes.number.isRequired
};
render(){
...
}
}
state
는 컴포넌트 내부에서 바뀔 수 있는 값을 의미한다. 즉 컴포넌트 자체적으로 지닌 값
props
는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이며, 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용할 수 있다.
컴포넌트에 state를 설정할 때는 다음과 같이 constructor 메서드를 작성한다.
constructor(props){
super(props);
this.state = {
number: 0
};
}
constructor를 작성할 때는 반드시 super(props)
를 호출해야 한다. 이 함수가 호출되면 현재 클래스형 컴포넌트가 상속받고 있는 react의 Component 클래스가 지닌 생성자 함수를 호출해 준다.
컴포넌트의 state는 객체 형식이어야 한다.
render() {
const { number } = this.state;
return (
<div>
<h1>{number}</h1>
<button
onClick={() => {
this.setState({ number: number + 1 });
}}
>
+1
</button>
</div>
);
}
render 함수에서 현재 state를 조회할 때는 this.state
를 조회하면 된다.
this.setState
함수는 인자로 전달된 객체 안에 들어 있는 값만 바꿔준다.
위에서 state의 초깃값을 지정하기 위해 constructor 메서드를 선언한 방식과는 다른 방식으로 state의 초깃값을 지정할 수 있다.
state = {
number: 0,
fixedNumber: 0,
};
this.setState로 state 값을 업데이트할 때는 상태가 비동기적으로 업데이트된다.
onClick={() => {
this.setState({ number: number + 1 });
this.setState({ number: this.state.number + 1 });
}}
this.setState를 두 번 사용함에도 불구하고 버튼을 클릭할 때 숫자가 1씩 더해진다.
this.setState를 사용한다고 해서 state 값이 바로 바뀌지는 않기 때문!
해결책: 객체 대신에 함수를 인자로 넣어준다.
this.setState((prevState, props) => {
return {
// 업데이트하고 싶은 내용
}
})
prevState
: 기존 상태, props
: 현재 지니고 있는 props
다음과 같이 사용한다.
<button
onClick={() => {
this.setState(prevState => {
return{
number: prevState.number + 1
};
});
// 위 아래는 같은 기능
this.setState(prevState => ({
number: prevState.number + 1
}));
}}
>
+1
</button>
setState의 두 번째 파라미터로 콜백 함수를 등록하여 작업 처리
this.setState(
{
number : number + 1
},
() => {
console.log('방금 setState가 호출되었습니다.');
}
);
useState
함수의 인자에는 상태의 초기값을 넣어준다. 클래스형 컴포넌트에서의 state 초기값을 객체 형태로 넣어주는 것과 달리 useState에서는 값의 형태는 자유.
const [message, setMessage] = useState('');
이 방법을 배열 비구조화 할당이라고 한다.
state 값을 바꾸어야 할 때는 setState 혹은 useState를 통해 전달받은 세터 함수를 사용해야 한다.
배열이나 객체를 업데이트해야 할 때는
1. 배열이나 객체 사본을 만들고 그 사본에 값을 업데이트
2. 그 사본의 상태를 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);
nextArray.map(item => item.id === 1? {...item, value: false} : item));
객체에 대한 사본을 만들 때는 spread 연산자 ... 사용
배열에 대한 사본을 만들 때는 배열의 내장 함수들을 활용