함수 컴포넌트 내부에서 상태를 정의하고, 이상태를 관리할 수 있게 해주는 훅
함수 컴포넌트는 매번 함수를 실행해 렌더링이 일어나고 함수 내의 값인 state의 값도 재실행 된다 이 값을 유지하고 사용하기 위해 리액트는 클로저를 활용
게으른 초기화(lazy initialization)
useState에 변수 대신 함수를 넣어서 초기값이 복잡하거나 무거운 연산(ex.localStorage, sessionStorage, 고차함수)이 요구 될 때 사용,이는 컴포넌트가 처음 구동될 때만 실행되고, 이후 리렌더링 시에는 실행되지 않음
//함수를 실행해 값을 반환한다
const [count, setCount] = useState(()=>Number.parseInt(window.localStorage.getItem(cacheKey)))
function Componenet(){
// 의존성 배열을 가진 형태
useEffect(()=>{
...
},[props,state])
// 아무런 값이 없는 빈 배열
useEffect(()=>{
...
},[])
// 배열 자체를 넣지 않고 생략
useEffect(()=>{
...
},[])
}
의존성 배열을 가진 형태 : 의존성에 있는 값을 보면서 이 의존성의 값이 이전과 다른게 하나라도 있으면(얕은 비교) 부수효과를 실행, useEffect의 본질이다.
아무런 값이 없는 빈 배열 : 리액트가 이 useEffect 는 비교할 의존성이 없다고 판단해 최초 렌더링 직후에 실행 된 다음 더 이상 실행되지 않음
배열 자체를 넣지 않고 생략 : 컴포넌트가 렌더링 될 때마다 useEffect가 실행
컴포넌트의 렌더링이 완료된 이후에 실행되기 때문에 csr에서 실행되는 것을 보장
클린업 함수
사용할 때 주의 점
import { useMemo } from 'react'
const memoizedValue = useMemo(()=>expensiveComputation(a,b),[a,b]) //인수로 어떠한 값을 반환하는 생성함수,해당 함수가 의존하는 값의 배열 형태
import { useState, useCallback } from 'react'
const [status, setStatus ] = useState(false);
const toggle = () => {
setStatus(!status)
}
const toggle = useCallback(toggle,[status]);
function RefComponent(){
const count = useRef(0)
const handleClick = () => {
count.current +=1;
}
return <button onClick={handleClick}>{count.current}</button>
}
const Context = createContext();
function Child() {
const value = useContext(Context);
return (
<div>자식이다</div>
);
}
function App() {
return (
<>
<Context.Provider value={{ hello: "react"}}>
<Context.Provider value={{ hello: "NextJS" }}>
<Child />
</Context.Provider>
</Context.Provider>
</>
);
}
ref 를 사용하는 방법 forwardRef
- ref 는 useRef에서 반환한 객체로, HTMLElement 접근으로 주로 사용
- 리액트 컴포넌트의 예약어로 별도로 선언돼 있지 않아도 prop으로 사용할수있다
- 네이밍의 완전한 자유보다는 ref 전달의 예측이 가능
- ref 를 받고자 하는 컴포넌트를 forwardRef 로 감싸야지 사용이 가능
const ChildComponent = forwardRef((props, ref) => { return <div> 내가 자식 컴포넌트 </div>; }); const ParentComonent = () => { const inputRef = useRef(); return ( <> <div>내가 부모 컴포넌트야</div> <ChildComponent ref={inputRef} /> </> ); };
const ChildComponent = forwardRef((props: defaultProps, ref) => {
useImperativeHandle(
ref,
() => ({
alert: () => alert(props.value),
}),
[props.value],
);
return <input ref={ref} {...props} />;
});
const ParentComonent = () => {
const inputRef = useRef();
const [text, setText] = useState("");
const handleClick = () => {
if (!inputRef.current) return;
inputRef.current.alert();
};
return (
<>
<ChildComponent ref={inputRef} value={text} />
<button onClick={handleClick}></button>
</>
);
};
실행 순서
1. 리액트 DOM 을 업데이트
2. useLayoutEffect를 실행
3. 브라우저에서 변경 사항을 반영
4. useEffect를 실행