#1. Hooks
1. Hooks의 개념
1) Hooks란?
- React가 16.8 버전으로 업데이트 되면서 새로 도입된 기능이다.
- 클래스형 컴포넌트의 단점을 극복하고자 나온 함수형 컴포넌트에 대한 기능이다.
- 즉, 함수 형태의 컴포넌트에서 사용되는 기술을 Hook이라 부른다.
- 또는 함수형 컴포넌트로도 클래스형 컴포넌트의 기능을 사용할 수 있도록 해주는 기술을 Hook이라 부른다.
2) 함수형 컴포넌트를 사용하는 이유
- 기존에 사용하던 클래스형 컴포넌트는 코드의 재사용성이 낮고, 코드 구성이 어려웠다. (클래스 문법이 어렵다)
- 기본적인 JS 문법을 알아야 사용이 가능했다.
- 클래스는 코드를 축소하기 힘들고, React의 최신 기술들이 클래스형 컴포넌트에 효과적으로 적용되지 않았다.
- 이러한 클래스의 단점들을 함수형 컴포넌트로 커버할 수 있었지만, 함수형 컴포넌트는 state나 life cycle을 다루는 기술이 없었다.
- 하지만, hook의 등장으로 state를 다룰 수 있게 되면서 함수형 컴포넌트의 사용률이 급격히 올라가게 되었다.
※ 클래스형 컴포넌트
// 클래스형 컴포넌트
import React, { Component } from 'react';
class App extends Component {
render(){
return (
//jsx
);
};
};
export default App;
※ 함수형 컴포넌트
// 함수형 컴포넌트
import React from 'react';
function App(){
return(
//jsx
);
};
export default App;
// 화살표 함수 표현도 가능하다.
const App = () => {};
3) Hook의 규칙
- Hook은 반드시 최상위에서만 호출해야한다.
- 반복문, 조건문 또는 중첩된 함수 내에서는 Hook을 실행할 수없다.
- React Component 내에서만 호출해야 한다. (js에서는 안됨)
4) React에서 이벤트 구현시 주의할 점
- 이벤트 리스너의 이름은 HTML 속성이 아닌 JSX에 의한 자바스크립트 프로퍼티 이므로 카멜표기법으로 작성해야한다.
- ex) onclick → onClick
- 이벤트 리스너에 전달할 이벤트 핸들러는 코드 형태가 아니라 반드시 함수 형태로 전달 해야한다.
- ex) onClick(( ) => { ... } )
2. 기본 Hook 함수들
1) useState
- 가장 기본적인 Hook 함수
- 함수형 컴포넌트에서 state값을 생성한다. (이 페이지 안에서 유효한 전역변수 같은 개념)
- 하나의 useState 함수는 하나의 값만 관리할 수 있다.
- state 값은 직접 변경할 수 없고, 반드시 setter를 통해서만 변경이 가능하다.
- 컴포넌트에서 관리해야 할 상태가 여러개라면 useState를 여러번 사용하면 된다.
- useState( ) 함수를 import하고 사용하는 경우.
import React, {useState} from 'react';
const [상태변수 , 변수에대한setter함수] = useState(초기값);
- useState( ) 함수를 import 하지 않고 직접 사용하는 경우 (결국 둘다 같은 방법이다)
import React from 'react';
const [상태변수 , 변수에대한setter함수] = React.useState(초기값);
※ 간단한 예제
- MyState.js
import React, { useState } from 'react';
const MyState = () => {
// 초기값을 빈문자열로 생성. 즉, myName = '';
const [myName, setMyName] = useState('');
// 이벤트 핸들러로 사용될 함수는 컴포넌트 함수 안에서 정의된다.
const onMyNameChange = (e) => {
// e.currentTarget은 jQuery의 $(this)에 해당함.
// 즉, 이벤트가 발생한 자신 (여기서는 input 태그)
setMyName(e.currentTarget.value);
};
return (
<div>
<h2>useState</h2>
{/* state값을 출력할 때는 단순히 변수값으로서 사용한다. */}
<h3>
{myName}님 안녕하세요.
</h3>
<hr />
<div>
<input
type="text"
value={myName}
onChange={onMyNameChange}
/>
</div>
</div>
);
};
export default MyState;
※ 출력결과
2) useEffect
- 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정하는 Hook이다.
- 기본적으로 렌더링 직후마다 실행되며, 두번째 파라미터 배열에 무엇을 넣는지에 따라 싱행되는 조건이 달라진다.
- 클래스형 컴포넌트의 componentDidMount와 componentDidUpdate를 합친 형태와 비슷하다.
// useEffect import
import React, { useEffect } from 'react';
- 렌더링 될 때마다 실행되는 함수 정의
- 최초 등장하거나 state 값이 변경될 때 모두 실행된다.
useEffect(() => {
.. 처리할 코드 ..
});
- 마운트 될 때만 실행되는 함수 정의
- 컴포넌트가 마운트될 때 최초 1회만 실행된다. (state 값이 변경 될 때는 실행되지 않는다.)
- 함수의 두번째 파라미터로 빈 배열을 넣어주면 된다.
useEffect(() => {
.. 처리할 코드 ..
}, []);
- 특정 값이 업데이트 될 때만 실행하고 싶을 때
- 두번째 파라미터로 전달되는 배열 안에 검사하고 싶은 값을 넣어주면 된다.
useEffect(() => {
.. 처리할 코드 ..
}, [값이름]);
- 언마운트될 때 실행
- 클로저(리턴되는 함수)를 명시한다.
- state 값이 변경되어 화면이 다시 렌더링 되거나 화면 이동 등의 이유로 컴포넌트가 사라질 때 실행된다.
- 오직 언마운트 될 때만 함수를 호출하고 싶다면 두번째 파라미터에 빈배열을 넣어주면 된다.
useEffect(() => {
return () => {
.. 처리할 코드 ..
}
},[]);
3) useRef
- 함수형 컴포넌트에서 ref를 쉽게 사용할 수 있도록 처리해 준다.
- 자바스크립트에서 document.getElementById( ) 나 document.querySelector( )로 DOM객체를 가져오는 과정을 React로 표현한 것으로 이해할 수 있다.
import React, { useRef } from 'react';
const MyRef = () => {
// HTML 태그를 리액트 안에서 참조할 수 있는 변수를 생성
const myDname = useRef();
const myLocation = useRef();
const myResult = useRef();
return (
<div>
<h2>useRef</h2>
{/* 미리 준비한 컴포넌트 참조변수와 HTML 태그를 연결 */}
<div>
<input type="text" ref={myDname} />
</div>
<div>
<input type="text" ref={myLocation} />
</div>
<h3>
입력값: <span ref={myResult} />
</h3>
<button
onClick={(e) => {
// 컴포넌트 참조변수를 사용해서 다른 HTML 태그에 접근 가능
// -> "참조변수.current" 해당 HTML을 의미하는 JS DOM 객체
// -> myDname.current와 document.querySelector or getElementByID 등으로 생성한 객체가 동일한 DOM객체이다.
const dname = myDname.current.value;
const loc = myLocation.current.value;
myResult.current.innerHTML = dname + ', ' + loc;
}}
>
클릭
</button>
</div>
);
};
export default MyRef;
※ 출력결과
4) useReducer
- usestate와 비슷하지만, 더 다양한 컴포넌트 상황에 따라 다양한 상태를 다른 값으로 업데이트 하고자 하는 경우 사용된다.
- usestate의 대체 함수로 이해하면 된다.
- state값이 다수의 하위값을 포함하거나 이를 활용하는 복잡한 로직을 만드는 경우 useState보다 useReducer를 선호한다.
import React, { useReducer } from 'react';
const [현재상태, reducer함수로전달할값] = useReducer(reducer함수, 초기값);
// usestate와 비슷하지만, 초기값 앞에 상태를 업데이트할 함수를 넣는다
- reducer 함수
- reducer 함수는 현재 상태와 업데이트를 위해 필요한 정보를 담은 action값을 전달 받아 새로운 상태를 반환하는 함수이다.
- useReducer 에서 전달 받은 값은 action 으로 들어와 state에 따라 action값을 어떻게 할지 정의한다.
function reducer(state, action) {
return ...;
}
// 함수명은 개발자 마음대로 해도 된다.
- useReducer의 구조
import React, { useReducer } from 'react';
function reducer(state, action) {
return ...;
}
const [현재상태, reducer함수로전달할값] = useReducer(reducer함수, 초기값);
- 어떤 이벤트에 의해 reducer함수로전달할값에 값이 들어오면 reducer함수의 action의 파라미터 값으로 이동한다.
- reducer 함수 내에서 action 파라미터를 통해 상태를 어떻게 할지 정의하고(대부분 switch문 사용) 그 값을 useReducer의 현재상태 값으로 보낸다.
- reducer 함수의 state는 현재상태가 업데이트 되기전의 값을 나타낸다.
※ 간단한 예제
import React, { useReducer } from 'react';
function setCounterValue(state, action) {
// action 값의 상태에 따른 state값을 처리
switch (action) {
case 'HELLO':
return state + 1; // 현재값 + 1
case 'WORLD':
return state - 1; // 현재값 - 1
default:
return 0;
}
}
const MyReducer = () => {
const [myCounter, setMyCounter] = useReducer(setCounterValue, 0);
// 현재상태, 함수로 보낼 값 reducer함수, 초기값
return (
<div>
<h2>MyReducer</h2>
<p>현재 카운트 값: {myCounter}</p>
<button type="button" onClick={(e) => setMyCounter('HELLO')}>
UP
</button>
<button type="button" onClick={(e) => setMyCounter('WORLD')}>
DOWN
</button>
<button type="button" onClick={(e) => setMyCounter('')}>
RESET
</button>
</div>
);
};
export default MyReducer;
※ 출력결과
5) useMemo
- 함수형 컴포넌트 내에서의 발생하는 연산을 최적화 할 수있다.
- 숫자, 문자열, 객체처럼 일반 값을 재사용하고자 할 경우 사용한다.
- useEffect의 특정값이 업데이트될 때만 실행하는 구조와 비슷하다.
- 두번째 파라미터인 배열에 설정된 state값이 이전 상태와 다를 경우에만 콜백을 실행한다.
const 변수명 = useMemo(() => 사용할함수, [검사할값]);
※ memoized 된 값을 반환한다
- 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술
※ 간단한 예제
// 출처: https://velog.io/@velopert/react-hooks
import React, { useMemo, useState } 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 nexList = list.concat(parseInt(number));
setList(nexList);
setNumber('');
};
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((v, i) => (
<li key={i}>{v}</li>
))}
</ul>
<div>
<b>평균 값: </b>
{getAverage(list)}
</div>
</div>
);
};
export default Average;
- 위 코드를 실행해보면 실행은 잘 되지만, input 내용을 수정 할 때마다 getAverage 함수가 호출된다.
- 이 때, 특정값이 바뀌었을 때만 연산을 실행하거나 바뀐 값이 없다면, 이전에 연산했던 결과를 다시 사용할수 있게 해주는게 useMemo이다.
// 출처: https://velog.io/@velopert/react-hooks
import React, { useMemo, useState } 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 nexList = list.concat(parseInt(number));
setList(nexList);
setNumber('');
};
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((v, i) => (
<li key={i}>{v}</li>
))}
</ul>
<div>
<b>평균 값: </b>
{avg}
</div>
</div>
);
};
export default Average;
- avg 변수에 useMemo를 사용하고, getAverage 함수를 선언하고, 검사할 값을 배열에 넣는다.
- 기존에 호출했던 getAverage함수 대신에 avg 변수 호출한다.
※출력 결과
6) useCallback
- useMemo와 비슷한 함수로 렌더링 성능 최적화에 사용된다
- memoized 된 콜백을 반환한다.
- 이벤트 핸들러 함수가 필요한 경우에만 생성할 수 있다.
- 일반적으로 이벤트 핸들러 함수를 선언하게 되면 컴포넌트가 리렌더링 될 때마다 이벤트 함수들이 새로 생성된다.
- 대부분의 경우에 이런 방식은 문제가 되지 않지만, 컴포넌트의 렌더링이 자주 발생하거나, 렌더링 해야할 컴포넌트의 개수가 많아진다면 문제가 된다.
import React, { useCallback, useState } from 'react';
const MyCallback = () => {
const [myText, setMyText] = useState('Hi!');
// 컴포넌트가 최초 렌더링 될 때 1회만 이벤트 핸들러 함수를 정의하고, 이후 부터는 계속적으로 재사용된다.
// 만약 두 번째 파라미터인 배열에 특정 state값을 지정할 경우 해당 값이 수정될 때만 이벤트가 정의된다.
const onInputChange = useCallback((e) => {
setMyText(e.currentTarget.value);
}, []);
return (
<div>
<h2>useCallback</h2>
<h3>{myText}</h3>
<input
type="text"
placeholder="input..."
onChange={onInputChange}
></input>
</div>
);
};
export default MyCallback;
※ 출력결과
'국비수업 > React' 카테고리의 다른 글
[React] Axios-hooks (0) | 2022.05.17 |
---|---|
[React] Axios 사용하기 (0) | 2022.05.15 |
[React] CSS 사용하기 (0) | 2022.04.26 |
[React] Props (Properties) (0) | 2022.04.25 |
[React] JSX (JavaScript eXtension) (0) | 2022.04.23 |