react hooks에 대해 정리합니다😊
React 버전 16.8부터 React요소로 새로 추가된 개념으로써, functionall component에서도 class component의 라이프사이클 기능을 사용할 수 있게 해주는 것입니다.
리액트 팀에서는 클래스 컴포넌트의 상태 관리를 위해서는 this
라는 자바스크립트의 개념을 알아야 하는데, 자바스크립트의에서의 this는 다른 언어의 this와는 다른 성격을 가지고 있어 사용하기 까다로운 점이 있다고 보고, 이 사항이 react의 사용에 좀 더 어려움을 가져다 준다고 보았습니다. 따라서 hooks라는 기능들을 추가함으로써 function 컴포넌트의 사용을 권장하고 있습니다.
🍕 클래스 컴포넌트를 제거할 계획은 없음으로 클래스 컴포넌트에 익숙하다고 해도 걱정 NO!
import React, { 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>
);
}
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// componentDidMount, componentDidUpdate와 비슷합니다
useEffect(() => {
// 브라우저 API를 이용해 문서의 타이틀을 업데이트합니다
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useEffect(() => {
console.log('마운트 될 때만 실행');
}, []);
특정 값이 업데이트될 때 실행하고 싶다면 배열에 그 값을 명시해주면 됨.
컴포넌트가 언마운트되기 전이나 업데이트되기 직전에 어떠한 작업을 수행하고 싶다면 뒷정리 함수를 반환해 주어야 함
useEffect(() => {
console.log('마운트 될 때만 실행');
return () => {
console.log('언마운트 전이나 업데이트 되기 직전 실행')
}
}, []);
리듀서
를 사용하는 hooks action
객체를 dispatch
함으로써 상태 값 변경import React, { useReducer } from 'react';
function reducer(state, action) {
switch(action.type) {
case 'INCREMENT':
return { value: state.value + 1};
case 'DECREMENT':
return { value: state.value - 1};
default:
return state; // 기존 상태 반환
}
};
const Counter = () => {
const [state, dispatch] = useReducer(reducer, { value: 0});
return (
<div>
<p>
현재 카운터 값은 <b>{state.value}</b>
</p>
<button onClick={() => dispatch({type: 'INCREMENT})}+1</button>
<button onClick={() => dispatch({type: 'INCREMENT})}+1</button>
</div>
)
}
메모이제이션
해, 변화가 있을 때만 다시 실행.import React, { useMemo } from "react";
const colorKor = useMemo(() => getColorKor(color), [color]);
const movieGenreKor = useMemo(() => getMovieGenreKor(movie), [movie]);
캐싱
해둔 값을 사용가상 돔
을 랜더링할 때, 변화를 감지하고 변화가 있는 부분을 다시 그려내는데 이때 만약 inline
스타일로 객체가 들어 있다면, 이는 무조건 다시 그려내게 됨🍕 객체는 키와 값 상관 없이 {} === {}는 false입니다. 같은 객체를 변수로 담고 있는 경우가 아니라면 모든 객체는 다른 주소값을 가지고 있다고 생각하면 됩니다!!!.
// 이번 예제는 벨로퍼트님의 react 강의에서 참고 했습니다.
import React, { useRef, useState, useMemo, useCallback } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
function countActiveUsers(users) {
console.log('활성 사용자 수를 세는중...');
return users.filter(user => user.active).length;
}
function App() {
const [inputs, setInputs] = useState({
username: '',
email: ''
});
const { username, email } = inputs;
const onChange = useCallback(
e => {
const { name, value } = e.target;
setInputs({
...inputs,
[name]: value
});
},
[inputs]
);
const [users, setUsers] = useState([
{
id: 1,
username: 'velopert',
email: 'public.velopert@gmail.com',
active: true
},
{
id: 2,
username: 'tester',
email: 'tester@example.com',
active: false
},
{
id: 3,
username: 'liz',
email: 'liz@example.com',
active: false
}
]);
const nextId = useRef(4);
const onCreate = useCallback(() => {
const user = {
id: nextId.current,
username,
email
};
setUsers(users.concat(user));
setInputs({
username: '',
email: ''
});
nextId.current += 1;
}, [users, username, email]);
const onRemove = useCallback(
id => {
// user.id 가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
// = user.id 가 id 인 것을 제거함
setUsers(users.filter(user => user.id !== id));
},
[users]
);
const onToggle = useCallback(
id => {
setUsers(
users.map(user =>
user.id === id ? { ...user, active: !user.active } : user
)
);
},
[users]
);
const count = useMemo(() => countActiveUsers(users), [users]);
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
/>
<UserList users={users} onRemove={onRemove} onToggle={onToggle} />
<div>활성사용자 수 : {count}</div>
</>
);
}
export default App;
DOM
객체를 직접 접근해 사용할 수 있게 해주는 hookcurrent
라는 값에 DOM 객체가 담기게 됨import React, {useRef, useState} from 'react'
const Example = () => {
const inputEl = useRef();
const [number, setNumber] = useState(0);
const onChange = (e) => {
setNumber(e.target.value);
inputEl.current.focus(); // onChange 함수가 호출 될 때마다 input dom에 focus가 됨
}
return (
<input ref={inputEl} value={number} onChange={onChange}/>
)
}
이 이외에도 많은 커스텀 hook이 존재합니다. 다른 개발자가 만든 다양한 Hooks를 사용하고 싶다면 다음 링크에서 확인할 수 있습니다.