3-1. 클래스형 컴포넌트
컴포넌트를 선언하는 방식은 두 가지이다
- 함수형 컴포넌트
- 클래스형 컴포넌트
위의 두 컴포넌트 모두 동일한 결과를 나타낸다
클래스형 vs 함수형
리액트의 버전이 올라가면서 현재는 둘의 차이점이 없다고 봐도 된다
아래는 리액트 공식 메뉴얼이다
결정적으로, Hook은 존재하는 코드와 함께 나란히 작동함으로써 점진적으로 적용할 수 있습니다.
그냥 함수형을 쓰자
3-3. props
props는 properties의 줄임말로 컴포넌트의 속성값이다
//in index.js
import React from 'react';
import ReactDOM from "react-dom";
const Test = ({name})=> {
return (
<div>
<h1>{name}</h1>
</div>
);
}
ReactDOM.render(
<Test name={'parents'} />,
document.getElementById("root")
);
- props값은 자신보다 상위 컴포넌트에서만 정해줄 수 있으며 그렇게 정해준 값은 읽기 전용값이 된다
props 기본값
defaultProps 객체에 값을 넣어두면 props값이 들어오지 않았을 때 넣어둔 값이 나온다
const Test = ({ name })=> {
return (
<div>
<h1>{name}</h1>
</div>
);
}
Test.defaultProps = {
name : 'default'
}
ReactDOM.render(
<Test />,
document.getElementById("root")
);
children
props 값 중에는 태그와 태그 사이에 있는 값을 저장해 놓는 children이 값이 존재
const Test = ({ name,children })=> {
return (
<div>
<h1>{name}</h1> // Title
<div>사잇값 : {children}</div> // '사잇값 : 이 값'
</div>
);
}
ReactDOM.render(
<Test name={'Title'}> 이 값 </Test>,
document.getElementById("root")
);
사잇값이 컴포넌트여도 가능
const Test = ({ name,children })=> {
return (
<div>
<h1>{name}</h1>
<div>사잇값 : {children}</div>
// '사잇값 :'
// 'im ch'
</div>
);
}
const Ch = ()=>{
return(
<div>im ch</div>
)
}
ReactDOM.render(
<Test name={'Title'}> <Ch/> </Test>,
document.getElementById("root")
);
클래스형에서의 props
class Test extends Component{
static defaultProps = {
name : 'default'
};
render() {
const {name, children} = this.props;
return (
<div>
<h1>{name}</h1>
<div>사잇값: {children}</div>
</div>
)
}
}
ReactDOM.render(
<Test name={'Title'}> 이 값 </Test>,
document.getElementById("root")
);
위에서 다루었던 것들을 클래스에서도 동일하게 사용가능하다
3-4. state
위에서 살펴본 props의 특성을 다시 보자
props값은 자신보다 상위 컴포넌트에서만 정해줄 수 있으며 그렇게 정해준 값은 읽기 전용
값이 된다.
props에 비해 컴포넌트 자신이 가지고 있는 값이며 컴포넌트 내부에서 수정이 가능한 값을 state라고 부른다
3-4-1. 클래스형 컴포넌트의 state
class Counter extends Component{
constructor(props) {
super(props);
this.state = {
number : 0
};
}
render() {
let {number} = this.state;
return(
<div>
<div>{number}</div>
<button className={'plus'} onClick={this.clickHandler}>+</button>
</div>
);
}
clickHandler=()=>{
this.setState({
number : this.state.number+1
});
}
}
ReactDOM.render(
<Counter />,
document.getElementById("root")
);
이 컴포넌트는 내부에 0으로 초기화된 number를 가지고 onClick이벤트의 setState를 이용해서 +를 누를 때 마다 number가 1씩 올라간다
constructor를 선언할 때 super(props)를 해주지 않으면 클래스 내에서 this를 사용할 수 없다
아이러니하게도 constructor 자체를 선언하지 않으면 아래와 같이 리액트가 자동으로 this를 할당해주어서 사용할 수 있게된다
class Counter extends Component{
state ={
number : 0
}
render() {
let {number} = this.state;
...
...
}
3-4-2. this.setState
위의 코드에서 clickHandler를 바꿔보자
clickHandler=()=>{
this.setState({
number : this.state.number+1
});
this.setState({
number : this.state.number+1
});
this.setState({
number : this.state.number+1
});
}
우리의 예상대로라면 이 코드는 +버튼을 눌러 이벤트를 발생시켰을 때 0→3 되어야하지만 실제론 0→1이 된다
왜 이런걸까?
컴포넌트의 리렌더링과 setState의 비동기적 업데이트
다음 조건들을 알아보자
- 컴포넌트가 리렌더링될 때 state의 값이 바뀐다
- state의 값을 바꾸는 setState는 비동기적이기 때문에 외부 스택에 쌓여있다 마지막에 처리된다
- 스택에 쌓여있는 setState들은 this.state의 값을 참조한다
살짝 감이 오는가..?
- number = 0 의 값을 바꾸기 위해 +를 누른다
- number의 값을 바꾸기 위해 호출된 setState들은 즉시 number의 값을 바꾸지않고 외부에서 대기하고 있다
- 외부 대기열에서 3개의 setState들은 모두 값이 0인 (this.state.)number을 참조하고 있다
- number : number(0) + 1
- number : number(0) + 1
- number : number(0) + 1
- 비동기 호출이 모두 끝나면 결국 number은 1로 리렌더링 된다
updater
이를 해결하기 위해 setState에 updater함수를 넣어주면 된다
setState(updater(state, props), [callback])
컴포넌트가 리렌더링될 때 state의 값이 바뀐다
는 점을 상기하라
updater의 state는 this.state와는 다르며 이 state는 리렌더링될 때 컴포넌트가 참조하는 객체라고 보면된다
즉 리렌더링될 때 updater의 state로 바뀌는 것
clickHandler=()=>{
this.setState((pre)=>{
return {number : pre.number+1}
});
this.setState((pre)=>{
return {number : pre.number+1}
});
}
여기서 받아오는 pre는 이전의 위와 비슷하게 작동하지만 3번의 부분이 다르다
- 외부 대기열에서 3개의 setState들은 (this.state.)number가 아닌 pre의 값을 참조한다(this.state.number은 계속해서 0이다)
- number : pre(0) + 1
- number : pre(1) + 1
- number : pre(2) + 1
결과 값은 3으로 우리가 원하는 값을 얻었다
3-4-3. 함수형 컴포넌트의 useState
const Counter = ()=>{
const [number,setNumber] = useState(0,); // number을 0으로 초기화
const clickHandler = ()=>{
//선언해둔 setNumber로 number를 증가
setNumber((number) => number+1);
}
return (
<div>
<div>{number}</div>
<button onClick={clickHandler}>+</button>
</div>
)
}
함수형 컴포넌트를 쓰자.
'React > 리액트를 다루는 기술' 카테고리의 다른 글
6. 컴포넌트 반복 (0) | 2021.01.17 |
---|---|
5. ref: DOM에 이름 달기 (0) | 2021.01.15 |
4. 이벤트 핸들링 (0) | 2021.01.12 |
2. JSX (0) | 2021.01.08 |
1. 리액트 시작 (0) | 2021.01.06 |