- useState
- useEffect
- useContext
- useReducer
- useCallback
- useMemo
- useRef
- useImperativeHandle
- useLayoutEffect
- useDebugValue
const [state, setState] = useState(initialState);첫λ²μ§Έ μΈμλ‘ μ΄κΈ°κ° μ λ£μ΄μ€λ€. useState λ μ°λ¦¬κ° λ§μ΄ μ¬μ©νλ state μ΄κΈ°ν μμ
κ³Ό λμΌνλ€κ³ μκ°νλ©΄ μ½λ€. μμ±μ μ°λ¦¬λ λ°°μ΄μ λ°μ μ¬ μ μλ€.
λͺ¨λ Hookμ 2κ°μ μΈμλ₯Ό λ°°μ΄λ‘ λ°μμ¨λ€.(λλ¬Όκ² μλ κ²λ μλ€.)
λ°°μ΄μ 첫λ²μ§Έλ μ°λ¦¬κ° λ겨주μλ μ΄κΈ°ν κ°μ΄ λ€μ΄μ€κ³ μ΄νμλ λ³κ²½λ κ°μ΄ λμ΄μ€κ² λλ€. λλ²μ§Έλ κ°λ₯Ό λ³κ²½νλ ν¨μλ€.
re-renderκ° λ κ²½μ° useStateμ μν΄ λ°νλ 첫 λ²μ§Έ κ°μ νμ μ λ°μ΄νΈλ₯Ό μ μ©ν ν κ°μ₯ μ΅κ·Ό μνκ° λλ€.
μμλ μ°λ¦¬λ μΈμλ‘ ν¨μλ₯Ό 보λΌμ μλ€. κ·Έλ¬λ κΈ°μ‘΄μ μ°λ¦¬κ° μ¬μ©νλ setState λ©μλμλ λ¬λΌμ μλμΌλ‘ λ³ν©μ μμΌμ£Όμ§ μλλ€.
μ¦ μ°λ¦¬κ° λ§λ€λ λ§λ€ νμμ λ°λΌ λ³ν©μ ν΄μ€μΌνλ€.
setState(prevState => {
// Object.assign would also work
return {...prevState, ...updatedValues}; // κ°λ¨νκ² spreadλ₯Ό μ¬μ©ν΄μ μλ‘ μμ±
});initial state μ μμ ν¨μλ₯Ό μ¬μ©ν μ μλ€. 리μ‘νΈ μ¬μ΄νΈμμ ννμΌλ‘λ κ° λΉμΌ κ³μ° μ΄λΌλ©΄ ν¨μλ₯Ό μ¬μ©ν΄μ νννλΌκ³ νλ€.
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});κ°μ κ°μ λ€μ μ
λ°μ΄νΈλ₯Ό νλλΌλ 리μ‘νΈμμλ μμμ re-render νκ±°λ effect λ₯Ό λ°μμν€μ§ μλλ€.(Object.isλ₯Ό μ¬μ©ν΄μ λΉκ΅νλ€κ³ ν¨_μ½μΌλ©΄ μ μ©ν¨)
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});κΈ°λ³Έμ μΌλ‘ λͺ¨λ λ λλ§μ΄ μλ£λ νμ μ€νμ΄ λλ€.
μ΄λ€ value κ° λ°λμμλ μ€νλλλ‘ ν μ μλ€.(λ΄κ° λ°λΌλ³΄κ³ μΆμ μΈμλ₯Ό λ£μ μ μλ€.)
νλ©΄μ λ λκΈ° μ μ μ 리λ₯Ό ν λ μ¬μ©ν μ μλ€.(dispose()μ κ°μ λλμ)
μλμ μμλ₯Ό λ³΄κ² λλ©΄ returnμΌλ‘ λ§λ ν¨μκ° μ 리λ₯Ό νλ ν¨μμ΄λ€.
useEffect(() => {
const subscription = props.source.subscribe();
return () => {
// Clean up the subscription
subscription.unsubscribe();
};
});λ©λͺ¨λ¦¬ λΆμ‘±μ λ°©μ§ννκΈ° μν΄ μ»΄ν¬λνΈκ° UIλ‘ λΆν° μ κ±°λκΈ° μ μ μ€ννλ€.
λ§μ½μ ꡬλ μ μ·¨μνκΈ°μ μ λ€λ₯Έ effectκ° μ€νμ΄ λμ΄ κ΅¬λ μ νλ€λ©΄? μ΄λ¬ν μΌμ΄ λ°μνλ κ²μ λ§κ³ μΆλ€λ©΄?
componentDidMount λ componentDidUpdate κ³Όλ λ€λ₯΄κ² layoutκ³Ό paint κ° λλκ³ λμ useEffectκ° μ€νμ΄λλ€. μ΄λ κ² λλ λ§λ 곡ν΅μ λΆμμ©μ μμ΄μ μ ν©νλ€ λΌκ³ νλλ°, νλ©΄μμ μ
λ°μ΄νΈλλ κ²μ΄ λ©μΆλ νμμ΄ μΌμ΄λμ§ μμΌλκΉ κ·Έλ° κ²μ΄λ€.
μλ₯Ό λ€μ΄, μ¬μ©μκ° λ³Ό μμλ DOM λ³μ΄λ μκ°μ μΈ λΆμΌμΉλ₯Ό μΈμνμ§ λͺ»νλλ‘ λ€μ νμΈνΈ μ μ λκΈ°μ μΌλ‘ μ€νν΄μΌ νλ€.
useLayoutEffect λ useEffect λμΌν κΈ°λ₯μ΄μ§λ§ μ€νλλ μμ μ΄ λ€λ₯Έ Hook μ΄λ€. μ½κ² λ§ν¨λ©΄ μ€νλλ μμ μ΄ λ€λ₯΄λ€λ κ²μΈλ° useEffect λ μλμ μ§ν κΈμ¨μ κ°μ΄ μμ ν νλ©΄μ΄ κ·Έλ €μ‘λ€ λΌλ κ²μ 보μ₯ν μ μμ§λ§ useLayoutEffectλ μμ μ΄ Domμ λ³νλ μμ§λ§ repaint, reflowκ° λμ§ μμ μμ μ΄λΌκ³ μκ°νλ©΄ λ κ² κ°λ€.
useEffectλ λΈλΌμ°μ κ° paintν λ κΉμ§ μ°κΈ°λ₯Ό νμ§λ§ μλ‘μ΄ λ λλ§μ μ μμλ κ²μ΄ 보μ¦νλ€.
useEffect(
() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
},
[props.source],
);useEffect μλ 2λ²μ§Έ μΈμκ° μ‘΄μ¬νλ€. μ¬κΈ°μ λ€μ΄κ°λ λ°°μ΄μ λ΄κ° λ°λΌλ³Ό κ² μΌλ‘ μ¬κΈ°μλ props.source μ λ³κ²½μ΄ μΌμ΄λ¬μ κ²½μ°μλ§ μλνκ² λλ€.
λ§μ½μ μΈμμ μ무κ²λ μλ€λ©΄ λ§μ΄νΈμμ μ€νλκ³ λ§μ΄νΈ ν΄μ μμλ μ 리νλ€.
const context = useContext(Context);react@16.3λΆν° μ§μμ ν Context λ₯Ό μ¬μ©ν μ μλλ‘ μ§μνλ κ²μ΄λ€. context object λ₯Ό λ°μμ νμ¬ context κ°μ λ°ννλ€.
providerκ° μ
λ°μ΄νΈλλ©΄ Hooksμ΄ μ€νλμ΄ μ΅μ μ κ°μΌλ‘ λΉμ°ν λκΈ°νκ° λλ€.
μ°λ¦¬κ° 리λμ€μμ λ§μ΄ 보λ Reducer μ λΉμ·νλ€κ³ μκ°νλ©΄ λλ€. κ·Έλ λ€κ³ νλ€.
const initialState = {count: 0};
// μ°λ¦¬κ° Reduxμμ λ§λ€λ Reducer λΆλΆ
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter({initialCount}) {
// μ΄κΈ°ν κ°κ³Ό Reducerλ₯Ό λ£μ΄μ€λ€.
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
);
}2λ²μ§Έ μΈμλ‘ μ΄κΈ°ν state λ₯Ό λ겨μ€λ€.(κ°λ¨νκ² μ΄κΈ°ννλ λ°©λ²)
const [state, dispatch] = useReducer(
reducer,
{count: initialCount}
);λ§μ½ λμ¨νκ² μ΄κΈ° state λ₯Ό λ§λ€κ³ μΆλ€λ©΄ 3λ²μ§Έ μΈμλ‘ init function μ λκΈ°μ
κ·Έλ¬λ©΄ init(initialArg) μ΄λ°μμΌλ‘ νΈμΆμ΄ λ κ²μ΄λ€.
function init(initialCount) {
return {count: initialCount};
}
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
case 'reset':
return init(action.payload);
default:
throw new Error();
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(reducer, initialCount, init);
return (
<>
Count: {state.count}
<button
onClick={() => dispatch({type: 'reset', payload: initialCount})}>
Reset
</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
);
}useState μ λμΌνκ² κ°μ κ°μ λκΈ°κ² λλ©΄ λ΄λΆμ μΌλ‘ λΉκ΅λ₯Ό ν΄μ μμ λ λλ§κ³Ό effectλ₯Ό μ€ννλ κ²μ λ§λλ€.
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);Returns a memoized callback.
μΈλΌμΈ μ½λ°±κ³Ό μ
λ ₯ λ°°μ΄μ μ λ¬ν©λλ€. useCallback μ μ
λ ₯ μ€ νλκ° λ³κ²½λ κ²½μ°μλ§ λ³κ²½λλ μ½λ°±μ memoized λ²μ μ λ°νν©λλ€
μ¦ a λλ b κ° λ³κ²½μ΄ λμλ€λ©΄ ν¨μ κ²°κ³Όλ₯Ό λ°ννλ€.
- λμΌν νν
useCallback(fn, inputs) //is equivalent to
useMemo(() => fn, inputs). const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);Returns a memoized value.
λ λλ§λλ λμ μ useMemoμ μ λ¬λ ν¨μκ° μ€νμ΄ λλ€.
μ¦, μ¬μ©νλλ° μμ΄μ μ‘°μ¬ν΄μΌνλ€. λ λλ§λμ νμ§μλ κ²μ νμ§ μμμΌνλ€. side effectλ₯Ό μν΄ useEffectλ₯Ό μ¬μ©ν΄μΌνλ κ²μ΄λ€.
useEffect μ λμΌνκ² λ°°μ΄μ΄ λμ΄κ°μ§ μμ κ²½μ° λ§€μκ° μ²«λ²μ§Έ λ§€κ°λ³μλ₯Ό νκ² λλ€.
μ±λ₯ μ΅μ νλ₯Ό μν΄μ useMemoλ₯Ό μ¬μ©ν μ μμ κ²μΌλ‘ μκ°μ΄ λλ€.
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>);
} useImperativeHandle(ref, createHandle, [inputs])useImperativeHandle μ ref λ₯Ό μ¬μ©ν λ λΆλͺ¨ κ΅¬μ± μμμ λ
ΈμΆλλ μΈμ€ν΄μ€ κ°μ μ¬μ©μ μ μν©λλ€.
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);μλͺ
μ useEffectμ λμΌνμ§λ§ λͺ¨λ DOM λ³μ΄ νμ λκΈ°μ μΌλ‘ μμ λ©λλ€.
useLayoutEffect λ΄λΆμμ μμ½λ μ
λ°μ΄νΈλ λΈλΌμ°μ κ° νμΈνΈν μ μκΈ° μ μ λκΈ°μ μΌλ‘ νλ¬μλ©λλ€.
μ΄κ²μ μ¬μ©νμ¬ DOMμμ λ μ΄μμμ μ½κ³ λκΈ°μ μΌλ‘ λ€μ λ λλ§ν©λλ€.
μκ°μ μΈ μ
λ°μ΄νΈλ₯Ό λ§μ§ μλλ‘ useEffectλ₯Ό μ¬μ©νκΈ°λ₯Ό κΆμ₯ν¨
useDebugValueλ React DevToolsμμ μ¬μ©μ μ μ νν¬ λ μ΄λΈμ νμνλ λ° μ¬μ©ν μ μμ΅λλ€.
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// ...
// Show a label in DevTools next to this Hook
// e.g. "FriendStatus: Online"
useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
} useDebugValue(date, date => date.toDateString());