- Today
- Total
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 에러
- javascript
- Redux
- 주식차트
- 주식
- nextjs
- typescript
- Firebase
- Coin
- 리액트
- 차트만들기
- 채팅
- typeorm
- nestjs
- websocket
- 3주차
- 차트구현
- react
- rtk
- 비전공자
- API
- error
- graphql
- 항해99
- 코인
- Flutter
- 코인차트
- 차트
- chart
- apollo
Act99 기술블로그
[React] class 형 컴포넌트 vs function 형 컴포넌트 본문
클래스형 컴포넌트 vs 함수형 컴포넌트
현재 리액트 공식문서에서는 함수형 컴포넌트와 훅을 사용하는 것을 권장하고 있다. 컴포넌트란 템플릿 기능 뿐만 아니라 데이터가 주여졌을 때 이에 맞추어 UI를 만들어주는 기능을 하며, 라이플 사이클 API 를 통해 컴포넌트가 화면에 나타날 때, 사라질 때, 변화할 때 작업들을 사용할 수 있다.
물론 클래스형 컴포넌트와 함수형 컴포넌트는 하는 일은 동일하지만, 코드 구조에서 약간의 차이가 있으며, 엄밀히 말하면 클래스 컴포넌트는 라이프 사이클 기능과 state 관리 기능이 코드에 구현되며, 함수형 컴포넌트는 hook 을 통해 라이프 사이클 기능과 state 관리 기능 코드를 짤 수 있다. 또한, 함수형 컴포넌트는 클래스형 컴포넌트보다 선언하기 좀 더 편하고, 메모리 자원을 덜 사용한다는 장점이 있다. 과거, 함수형 컴포넌트는 state 와 라이프 사이클 API 를 사용할 수 없다는 단점이 있었지만 현재, 훅에 의해 이 모든 문제가 해결되었다.
// 클래스형 컴포넌트
class ClassComponent extends Component {
state = { count: 0 }
increase = () => {
this.setState(({ count }) => ({ count: count + 1 })
}
render() {
return (
<div>
<p>count: {this.state.count}</p>
<button onClick={this.increase}>INCREASE</button>
</div>
)
}
}
// 함수형 컴포넌트
function FunctionComponent(props) {
const [count, setCount] = useState(props.count)
return (
<div>
<p>count: {count}</p>
<button onClick={() => setCount(count + 1)}>INCREASE</button>
</div>
)
}
React Hooks
그렇다면 React Hooks에는 어떤 것들이 있을까?
1. useState
useState 는 가장 기본적인 훅이며, 컴포넌트 안에서 상태 관리를 해야하는 일이 발생한다면 이 훅을 사용한다.
import React, { useState } from 'react';
const Counter = () => {
const [value, setValue] = useState(0);
return (
<div>
<p>
현재 카운터 값은 <b>{value}</b> 입니다.
</p>
<button onClick={() => setValue(value + 1)}>+1</button>
<button onClick={() => setValue(value - 1)}>-1</button>
</div>
);
};
2. useEffect
useEffect는 리액트 컴포넌트가 리렌더링 될 때마다 특정한 작업을 수행하도록 설정할 수 있게 하는 Hook 이다. 클래스형 컴포넌트로 치면, componentDidMount, componentDidUpdate, componentWillUnmount 의 기능을 제공한다.
import React, { useState, useEffect } from 'react';
const Info = () => {
const [name, setName] = useState('');
const [nickname, setNickname] = useState('');
useEffect(() => {
console.log('렌더링이 완료되었습니다!');
console.log({
name,
nickname
});
});
const onChangeName = e => {
setName(e.target.value);
};
const onChangeNickname = e => {
setNickname(e.target.value);
};
return (
(...)
);
};
export default Info;
3. uesContext
이 훅을 사용하면 부모 컴퍼넌트에서 자식 컴퍼넌트로 넘기는 props 과정에서 props drilling 지옥에 빠지지 않는다. 또한, 함수형 컴포넌트에서 Context를 보다 쉽게 사용할 수 있다. 자세한 것은 이 블로그에 useContext vs 상태관리 툴 차이 게시물을 보면 된다.
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext('black');
const ContextSample = () => {
const theme = useContext(ThemeContext);
const style = {
width: '24px',
height: '24px',
background: theme
};
return <div style={style} />;
};
export default ContextSample;
4. useReducer
이 훅은 useState보다 컴포넌트에서 더 다양한 상황에 다양한 상태를 다른 값으로 업데이트 시켜주고 싶을 때 사용한다. 리듀서라는 개념은 Redux를 사용하는 유저는 쉽게 이해할 수 있으며, 이 리듀서 개념은 현재 상태와 업데이트를 위해 필요한 정보를 담은 action 값을 받아 새로운 상태를 반환해주는 함수이다. 이 리듀서 함수의 특징은 새로운 상태를 만들 때는 꼭 불변성을 지켜주어야 한다는 것이 있다.
5. useMemo
useMemo를 사용한다면 함수형 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있다. 단순히 useState 훅을 사용하면 state가 수정될 때마다 setState 함수가 반복적으로 호출되며, 렌더링 될 때마다 함수 내에서 계산이 진행되는데, useMemo Hook 을 사용하면 이러한 작업을 최적화 시킬 수 있다 .렌더링 하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행하며, 만약 원하는 값이 바뀐 것이 아니라면 이전에 연산했던 결과를 다시 사용하는 방식이다.
import React, { useState, useMemo } from 'react';
const getAverage = numbers => {
console.log('평균값 계산중..');
if (numbers.length === 0) return 0;
const sum = numbers.reduce((a, b) => a + b);
return sum / numbers.length;
};
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState('');
const onChange = e => {
setNumber(e.target.value);
};
const onInsert = e => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
};
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
<div>
<b>평균 값:</b> {avg}
</div>
</div>
);
};
export default Average;
6. useCallback
useCallback 훅은 useMemo 와 상당히 비슷한 함수이다. 주로 렌더링 성능을 최적화해야 하는 상황에서 사용하며, 이벤트 핸들러 함수를 필요할 때만 생성할 수 있는 기능을 제공한다.
import React, { useState, useMemo, useCallback } from 'react';
const getAverage = numbers => {
console.log('평균값 계산중..');
if (numbers.length === 0) return 0;
const sum = numbers.reduce((a, b) => a + b);
return sum / numbers.length;
};
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState('');
const onChange = useCallback(e => {
setNumber(e.target.value);
}, []); // 컴포넌트가 처음 렌더링 될 때만 함수 생성
const onInsert = useCallback(
e => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
},
[number, list]
); // number 혹은 list 가 바뀌었을 때만 함수 생성
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
<div>
<b>평균값:</b> {avg}
</div>
</div>
);
};
export default Average;
그리고, 다음 예시를 보면 useMemo 와 useCallback이 어느정도 동일한 기능을 제공한다고 볼 수 있다.
useCallback(() => {
console.log('hello world!');
}, [])
useMemo(() => {
const fn = () => {
console.log('hello world!');
};
return fn;
}, [])
7. useRef
useRef Hook 은 함수형 컴포넌트에서 ref를 쉽게 사용할 수 있도록 해준다. useRef 를 사용하여 ref 를 설정하면 useRef 를 통해 만든 객체 안의 current 값이 실제 엘리먼트를 가르키게 된다.
이 외에도 react hook form, useInput, useWindowSize 등의 커스텀 훅이 존재하며, 다른 개발자들이 만든 Hooks 도 라이브러리로 설치하여 사용할 수 있다.
'개발팁저장소 > react' 카테고리의 다른 글
[항해99 실전프로젝트 3주차 / websocket ] (0) | 2022.03.15 |
---|---|
[항해99 주특기 3주차 심화과정] 실시간 SNS 만들기 - 과제 종료 (0) | 2022.02.09 |
[React] Context API 와 상태관리 툴의 차이 (0) | 2022.02.03 |
[React + Firebase] export 'default' (imported as 'firebase') was not found in 'firebase/app' 오류생길 때 (0) | 2022.02.02 |
만약 npx create-react-app 이 실행되지 않을 경우/ please remove any global installs with one of the following commands (0) | 2022.01.26 |