react hook
state
useState (<-> useLayoutEffect: 동기방식)
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = **useState**(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
※ 같은 state 여러 번 업데이트하기
state가 변경되어 컴포넌트가 리렌더링될 때는 state가 전부 다 업데이트 될 때까지 기다렸다가 한 번에 리렌더링한다. 따라서 아래와 같은 방식으로 하면 number는 4가 아니라 2가 된다
const [number, setNumber] = useState(1);
const func = () => {
setNumber(number*2);
setNumber(number*2);
}
의도대로 값을 바꾸고 싶으면 setNumber에 값이 아니라 함수를 넘겨준다
const func = () => {
setNumber((prevState) => {
return prevState*2;
});
setNumber((prevState) => prevState*2);
//둘 다 같은 의미
}
useEffect
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
}
import React, { useState, useEffect } from 'react';
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
컴포넌트가 마운트 해제될 때, 다음 차례의 effect를 실행하기 전에 이전의 렌더링에서 파생된 effect 또한 정리
useRef
import React, { useState, useRef } from 'react';
const App = () => {
const [count, setCount] = useState(0);
const countRef = useRef(0);
const increaseCountState = () => {
setCount(count + 1):;
};
const increaseCountRef () => {
countRef.current = countRef.current + 1;
};
return (
<div>
<p>State: {count}</p>
<p>Ref: {countRef.current}</p>
<button onClick={increaseCountState}>State 증가</button>
<button onClick={increaseCountRef}>Ref 증가</button>
</div>
);
}
getElementById
, querySelector
와 유사)import { useRef, useEffect } from "react";
function App() {
const inputRef = useRef();
function focus() {
inputRef.current.focus();
console.log(inputRef.current);
}
return (
<div>
<input ref={inputRef} type="text" placeholder="아이디 또는 이메일" />
<button>Login</button>
<br />
<button onClick={focus}>focus</button>
</div>
);
}
export default App;
useContext
useReducer
현재 상태와 액션 객체를 파라미터로 받아와서 새로운 상태를 반환해주는 함수
function reducer(state, action) {
return { ... }; // 불변성을 지키면서 업데이트한 새로운 상태를 반환합니다
}
{
type: 'DECREMENT'
},
{
type: 'ADD_TODO',
todo: {
id: 1,
text: 'useReducer 배우기',
done: false,
}
}
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: 'DECREMENT' })}>-1</button>
</div>
);
};
export default Counter;
컴포넌트 최적화
useMemo
import React, { useState, useMemo } from 'react';
function complicateFunc() {
//시간이 오래 걸리고 복잡한 연산을 하는 함수
}
function App() {
const [state, setState] = useState('');
const result = useMemo(() => {
return complicateFunc(state);
}, [state]);
...
}
export default App;
useCallback