[React Hook 시리즈 1]: 쓰는 이유, useState()

1. React hook 이란?
함수형 컴포넌트는 컴포넌트 내부의 state를 만들 수 없고, 컴포넌트의 생성, 변경, 소멸에 대한 이벤트인 라이프사이클 API를 사용할 수 없었다. 그저 상위 컴포넌트가 시키는 일만 처리하는 단순한 컴포넌트에만 사용됐다. 하지만 16.8 버전부터 훅(hook)이라는 개념이 도입되며, 이 둘을 해결할 수 있게 됐다. 두 가지 기능을 함수형 컴포넌트에 "hook into”, 끌어와 연결 한다고 해서 "hook"이라고 부른다. 또한 클래스 컴포넌트에서 귀찮게 사용되는 didMount, render, this 등 대신, 함수형 프로그래밍 스타일로 가독성 있게 코드를 작성할 수 있게 됐다.
Class Component
import { Component } from 'react';
class Example extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
Functional Component using hooks
import { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
-
함수형 컴포넌트의 코드가 훨씬 간결해지고, 가독성이 좋다.
-
하지만 Facebook이 Class Component를 꾸준히 지원한다고 약속했으니, 두 가지 방법 모두 알아두자
함수형 컴포넌트의 첫 번째 파라미터는 props값을 전달받는다.
function FuncComp(props){
return(<h1>{props.count}</h1>)
}
function FuncComp({count}){
return(<h1>{count}</h1>)
}
2. useState
- default 값 없이 useState()를 작성하면, state값은 undefined가 된다.
import {useState} from 'react'
function FuncComp(props){
var countState = useState(props.count)
// useState의 반환값: 배열
// useState(initValue)
var count = countState[0] // 첫 번째 값: state 값
var setCount = countState[1] // 두 번째 값: state를 바꾸는 함수
return(
<h1>{count}</h1>
<button onClick={()=>setCount(count+1)}>
)
}
최상위 레벨에서만 훅을 사용할 수 있다.
-hook 은 for문, if문, 중첩 함수 내에서 호출 될 수 없다.
import {useState} from 'react'
function Component(props){
var [count, setCount] = useState(props.count) ✅
function inner() {
var [count, setCount] = useState(props.count) ❌
}
if(count){
var [count, setCount] = useState(props.count) ❌
}
return(
var [count, setCount] = useState(props.count) ❌
<button onClick={()=>setCount(count+1)}></button>
)
}
3. useInput
import {useState} from "react"
const useInput = (initialValue, validator) => {
const [value, setValue] = useState(initialValue);
const onChange = (event) => {
const {
target: { value }
} = event;
let willUpdate = true;
if (typeof validator === "function") {
willUpdate = validator(value);
}
if (willUpdate) {
setValue(value);
}
};
return { value, onChange };
};
const App = () => {
const maxLen = (value) => value.length < 10;
const name = useInput("Mr.", maxLen);
return (
<>
<div className="APP">
<h1>Hello</h1>
<input placeholder="Name" {...name} />
</div>
</>
);
};
-
{value: "e", onChange: ƒ onChange()}
-
{value: "e2", onChange: ƒ onChange()}
-
{value: "e22", onChange: ƒ onChange()}
-
onChange: 값이 바뀔 때 마다 onChange함수가 계속 작동하며 유효성검사를 거쳐 DOM을 refresh한다.
2. onChange함수는 event를 갖고 있다. 다른 function에서 이벤트를 처리할 수 있기 때문에 혁명적인 일이다. 이벤트를 분리된 파일, 다른 entity에 연결해서 처리할 수 있다.
4. useTabs
import React, { useState } from "react";
const content = [
{
tab: "Section1",
content: "I am content1"
},
{
tab: "Section2",
content: "I am content2"
}
];
const useTabs = (initialTab, allTabs) => {
const [currentIndex, setCurrentIndex] = useState(initialTab);
if (!allTabs || !Array.isArray(allTabs)) {
return;
}
return {
currentItem: allTabs[currentIndex],
changeItem: setCurrentIndex
};
};
const App = () => {
const { currentItem, changeItem } = useTabs(0, content);
return (
<div className="App">
{content.map((section, index) => (
<button onClick={() => changeItem(index)}>{section.tab}</button>
))}
<div>{currentItem.content}</div>
</div>
);
};
export default App;