본 글은 노마더 코더의 실전형 리액트 Hooks 10개 강의를 들으며 작성한 글입니다.
React Hook이란?
Functional Component에서 State를 가질 수 있게 해주는 기능.
기존의 React에서는 class로 component를 선언하고 그 안에서만 state를 사용할 수 있었다.
리액트에는 2가지 component가 있는데 바로 Function Component와 Class Component이다.
(2021년 강의 버전에 따르면 useState, useEffect와 같은 Hook을 통해 Function Component로 통합할 수 있다.)
Function Component
import React from "react";
function App() {
return (
<div>
<span>I m function component</span>
</div>
);
}
export default App;
function component는 return 값으로 html을 반환한다.
react는 return된 html을 그려준다.
Class Component
import React from "react";
class App extends React.Component {
render() {
return <h1>I m a class component</h1>;
}
}
export default App;
class component에는 return이 없다. 왜? function이 아니라 class니까.
그래서 class component는 React.Component로부터 상속받은 render 함수를 통해 html을 그려준다.
react는 자동적으로 모든 class component의 render 함수를 실행하고자 하기 때문에
render 함수를 통해 html을 그려줄 수 있는 것이다.
그렇다면 왜 class component를 써야할까?
import React from "react";
class App extends React.Component {
state = {
count: 0
};
render() {
return <h1>I m a {this.state.count}</h1>;
}
}
export default App;
바로 class component를 통해서만 state를 사용할 수 있기 때문이다.
state는 React.Component로부터 상속받은 object고 이는 당연하게도 function에서는 사용할 수 없다.
그래서 우리가 state를 사용하기 위해서는 function component가 아닌 class component로 접근해야한다.
use + 대문자로 작성하면 자동으로 Custom Hook으로 인식된다.
Hook은 조건문, 반복문, 중첩함수 안에서 호출 할 수 없고 React 함수 안에서만 호출할 수 있다.
import React from "react";
class App extends React.Component {
state = {
item: 1
};
render() {
const { item } = this.state;
return (
<div className="App">
<h1>{item}</h1>
<button onClick={this.incrementItem}>increment</button>
<button onClick={this.decrementItem}>decrement</button>
</div>
);
}
incrementItem = () => {
this.setState((state) => {
return {
item: state.item + 1
};
});
};
decrementItem = () => {
this.setState((state) => {
return {
item: state.item - 1
};
});
};
}
export default App;
Hook을 사용하면 state를 사용하기 위해 class component를 선언할 필요 없이
function component 안에서 State를 사용할 수 있게 된다.
더이상 render, this를 사용할 필요 없다!
위와 아래는 각각 같은 동작을 하는 코드를 class component와 hook을 이용한 function component로 짠 모습이다.
길이만 봐도 차이가 느껴진다.
import React, { useState } from "react";
function App() {
const [item, setItem] = useState(1);
const incrementItem = () => setItem((current) => current + 1);
const decrementItem = () => setItem((current) => current - 1);
return (
<div className="App">
<h1>{item}</h1>
<button onClick={incrementItem}>increment</button>
<button onClick={decrementItem}>decrement</button>
</div>
);
}
export default App;
이제 Hook을 필요성을 알았으니 다양한 훅들을 알아보자.
1. useState
setState 함수를 대체하는 훅이다.
import React, { useState } from "react";
function App() {
const [item, setItem] = useState(1);
const incrementItem = () => setItem((current) => current + 1);
const decrementItem = () => setItem((current) => current - 1);
return (
<div className="App">
<h1>{item}</h1>
<button onClick={incrementItem}>increment</button>
<button onClick={decrementItem}>decrement</button>
</div>
);
}
export default App;
useState() 함수는 반환값으로 [data, function] 배열을 넘겨준다.
data는 데이터가 저장되는 state이고 function은 data를 수정할 수 있게 해주는 함수이다.
useState 내부 파라미터를 통해 data를 초기화할 수 있다.
useState는 최상위에서만 호출할 수 있다.
2. useEffect
useEffect는 componentDidMount(), componentDidUpdate(), componentWillUnmount()의 역할을 대신한다.
import React, { useState, useEffect } from "react";
const App = () => {
const sayHello = () => {
console.log("Hello");
};
const [number, setNumber] = useState(0);
const [anumber, setANumber] = useState(0);
useEffect(sayHello, [number]);
return (
<div className="App">
<div>Hi</div>
<button onClick={() => setNumber(number + 1)}>{number}</button>
<button onClick={() => setANumber(anumber + 1)}>{anumber}</button>
</div>
);
};
export default App;
useEffect는 인자로 [function, dependency]를 받는데
function은 실행할 함수, dependency는 감시할 state를 의미한다.
만약 dependency가 아에 적혀있지 않다면 모든 state가 mount되거나 update시 실행된다.
[]과 같이 비어있다면 페이지가 시작하는 최초에만 실행되고 state update 시에는 실행되지 않으며,
[name]과 같이 state를 가진다면 해당 state가 update 될 때만 실행된다.
import React, { useState, useEffect, useRef } from "react";
const useClick = (onClick) => {
const element = useRef();
useEffect(() => {
if (element.current) {
element.current.addEventListener("click", onClick);
}
return () => { //componentWillUnmount() 실행 시 실행
if (element.current) {
element.current.removeEventListener("click", onClick);
}
}
}, []);
return element;
};
const App = () => {
const sayHello = () => console.log("Hello");
const title = useClick(sayHello);
return (
<div className="App">
<div ref={title}>Hi</div>
</div>
);
};
export default App;
useEffect는 return으로 function을 줄 수 있는데
이 function은 componentWillUnmount()가 실행될 때 실행된다.
위 코드는 최초 페이지 로딩 시에 useEffect()를 통해 element에 Event Listener를 붙여주었다가
element가 제거되면 Event Listener를 제거해주는 코드이다.
element 제거 시 return () => ... 함수가 실행되거 Event Listener를 제거한다.
3. useRef
reference는 document.getElementById()처럼 component의 어떤 부분을 선택할 수 있는 훅이다.
import React, { useState, useEffect, useRef } from "react";
const App = () => {
const potato = useRef();
setTimeout(() => potato.current.focus(), 5000);
return (
<div className="App">
<div>Hi</div>
<input ref={potato} placeholder="la" />
</div>
);
};
export default App;
만약 위와 같은 함수가 있다면 5초 뒤에 input 칸이 focus된다.
useRef와 ref={potato} 속성을 통해 input을 선택해서 setTimeout에서 focus 해주도록 설정했기 때문.
'Frontend > React' 카테고리의 다른 글
프론트엔드에서의 TDD (0) | 2023.04.08 |
---|---|
[React] useAxios (0) | 2022.02.03 |
[React] 6. React Router (0) | 2021.11.25 |
[React] 5. Effect (0) | 2021.11.24 |
[React] 4. CREATE REACT APP (0) | 2021.11.24 |