진짜 Hooks 대가리 깬다 진짜 친절하고 자세하게 정리하고 더이상 까먹지 말아여지
책은 리액트를 다루는 기술, 예제는 별코딩 영상 참고했다.
https://ko.legacy.reactjs.org/docs/state-and-lifecycle.html#adding-lifecycle-methods-to-a-class
State and Lifecycle – React
A JavaScript library for building user interfaces
ko.legacy.reactjs.org
권장) hook하기전에 리액트 state lifecycle부터 이해하면 좋음
1. useState
2. useEffect
3. useReducer
4. useMemo
5. useCallback
6. useRef
그럼 시작!
하기전에 hooks에 대한 설명
승훈이가 물어봐서 나도 정리가 됐다.
hooks는 상태관리하는 기능? 이라고 본다. 리액트 내장 기능이고 커스텀해서 사용할 수 있다.
리액트는 컴포넌트 재사용상도 훌륭하고 가상돔 덕에 화면 리랜더링이 끝내주게 된다.
거기다 hooks까정 사용해주면? 불필요한 랜더링까지 잡아줘서 우주최강이 된다 이말씀
그럼 진짜 시작!
useState
가장 기본적인 hooks이다.
state값과 state 값을 업데이트하는 함수를 반환하는 함수이고
일반적으로 함수 내의 변수는 함수가 종료되면 사라지지만 useState를 사용해 변수의 상태를 초기화하면
리액트에 의해 해당 변수는 사라지지않고 계속 관리될 수 있다.
이를 어려운 말로 함수형 컴포넌트에서도 가변적인 상태를 지닐 수 있게 해준다. 라고 한다.
const [value, setValue] = useState(0)
value = state
setValue = state 상태를 변환시켜주는 애
useState(0) = 기본값을 선언해준다.
state값이 변경될때마다 화면은 리렌더링이 되므로 해당 사항을 신경써서 화면배치 하는것이 좋다.
+ 번외기능
화면이 처음 mount 될 때 엄청 무거운 작업이 동반된다 가정해보자
이런식으로 콜백을 선언해준다면 맨 처음 렌더링이 될 때, 한번만 호출된다.
useEffect
useEffect는 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook이다.
useEffect 함수를 컴포넌트 함수 내에서 호출하게 되면 해당 함수내에 정의된 변수를 감지하는것이 가능하며.
이 때문에 uesEffet함수를 컴포넌트 함수 내에서 사용하는 것이다.
useEffect = (()=>{}); // 랜더링 될 때마다 실행
useEffect = (()=> {},[value]); //마운트 + Dependency Array가 갱신될때마다 실행
첫번째 예제의 경우 랜더링이 될때, 다시 랜더링 될때 만 실행된다.
두번째 예제처럼 사용하게 될 경우 마운트+[dependency]가 변경될때만 실행되어 불필요한 렌더링을 줄일 수 있다.
그리고 언마운트 될 때, 즉 작업이 끝났을때 함수를 호출할 수 있도록 하는 cleanup작업도 진행할 수 있다.
useEffect = (()=>{
...
return () => {
console.log("위의 작업이 끝나면 호출된다);
};
},[]);
위와같이 return 값으로 해당 useEffect내에 선언한 작업이 unMount될때 혹은 다음 useEffect가 호출되기 직전에 사용되야하는 함수가 있을경우 해당과 같이 작업하면 된다.
+ 이따 useMemo에서 자세하게 설명하겠지만
dependency array는 원시(Primitive)타입이다. 즉, 값으로 비교(===)를 하고있기 때문에 객체(object) 타입의 변화는 감지가 정확하지 않을 수 있다. 원시타입으로만 dependency array를 설정할 것
useReducer
useState보다 더 다양한 컴포넌트 상황에 따라 다양한 상태를 다른 값으로 업데이트 해주고 싶을때 사용하는 Hook이다.
리듀서는 현재 상태, 그리고 업데이트를 위해 필요한 정보를 담은 액션값을 전달 받아 새로운 상태를 반환하는 함수이다.
리듀서 함수에서 새로운 상태를 만들때는 반드시 불변성을 지켜주어야 한다.
Dispatch : 요청자
Action : 요구사항
Reducer: 전달 매체, 업데이트 하는 역할
State: 최종 변경 내용(상태)
요청자의 요구사항에 맞게 예금/출금/송금 등 복잡한 일을 처리할 수 있다.
import React, { useReducer } from 'react';
function reducer(state, action) {
// action.type에 따라 다른 작업 수행
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;
이런식으로 타입에 맞게 state값을 쉽게 처리할 수 있게 만드는 것이 이번 hook의 핵심이다.
또, 인풋 상태 관리를 할 수 있다. 기존 useState로 관리하게 될 경우 상태가 여러개면 여러번 사용해야하는 이슈가 있었지만
리듀서를 통해 간편하게 관리할 수 있다.
import React, { useReducer } from 'react';
function reducer(state, action) {
return {
...state,
[action.name]: action.value
};
}
const Info = () => {
const [state, dispatch] = useReducer(reducer, {
name: '',
nickname: ''
});
const { name, nickname } = state;
const onChange = e => {
dispatch(e.target);
};
return (
<div>
<div>
<input name="name" value={name} onChange={onChange} />
<input name="nickname" value={nickname} onChange={onChange} />
</div>
<div>
<div>
<b>이름:</b> {name}
</div>
<div>
<b>닉네임: </b>
{nickname}
</div>
</div>
</div>
);
};
export default Info;
useMemo
컴포넌트 최적화를 위해 사용하는 hook이다. 비용이 많이 드는 작업의 경우 관련 작업을 캐싱하여 연산을 최적화 시킨다.
함수형 컴포넌트에서 호출이 된다는 의미는 렌더링이 된다는 것이다.(렌더링은 내부 변수를 모두 초기화 )
연산이 오래 걸리는 비싼 작업이 페이지 내에 로딩된다 가정해 보자
이때 새로 렌더링이 될 경우? 모두 다 날라가는 것이다 결국 새로 랜더링이 될 때 마다 비싼 작업이 반복되는 것
const value = useMemo(()=>{
return calculate();
},
[]); // Mount 될 경우에만 호출된다.
const value = useMemo(()=>{
return calculate();
},
[result]); // result값이 갱신 될 경우에만 호출된다.
첫번째의 경우 마운트 될 경우 콜백함수를 호출해서 value에다 메모이제이션 된 값을 넣어준다.
두번째 예제를 좀 더 구체적으로 설명해보자면
useMemo안에 콜백함수는 메모이제이션 해줄 값을 계산해서 리턴해주는 것이다.
뒤에 붙은 dependency 요소가 업데이트 될 때만 콜백함수를 다시 호출해서 메모이제이션 된 값을 다시 업데이트 해준다.
import React, { useState, useMemo } from 'react';
const getAverage = numbers => {
console.log('평균값 계산 중..');
if (numbers.length === 0) return 0;
const sum = numbers.reduce((a, b) => a + b);
return sum / numbers.length;
};
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState('');
const onChange = e => {
setNumber(e.target.value);
};
const onInsert = () => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
};
const avg = useMemo(() => getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
<div>
<b>평균값:</b> {avg}
</div>
</div>
);
};
export default Average;
이런식으로 list가 바뀔때만 useMemo를 통해 getAverage를 이용한 메모이제이션을 구현해줄 수 있다.
+ 원시타입으로 비교 되는 useEffec와 메모이제이션으로 저장이 되는 useMemo를 사용하여 이런식으로 활용이 가능하다.
위처럼 사용하지않고 단순히, 오브젝트로 의존성 배열에 넣을 경우 useEffect는 의도와 상관없이 계속 렌더링이 될 것이다.
useCallback
useMemo와 상당히 비슷한 함수이다.
해당 함수도 렌더링 성능을 최적화해야 하는 상황에서 사용하는데 이 Hook을 사용하면 만들어 놨던 함수를 재사용 할 수 있다.
useMemo는 어떠한 "값"을 메모이징하기 위한 것이고, useCallback은 어떠한 "함수"를 메모이징하기 위한 것
somefunction은 함수 객체가 들어있는 메모리의 주소를 가지고있다.
app펑션이 랜더링 될 때, somefunction 역시 초기화 되므로 함수 객체도 새로 만들어져서 다른 메모리 공간에 저장이 된다.
이렇게 될 경우 useEffect입장에서는 "somefunction이 변경되었으니 다시 호출하자!" 가 되는것이다. 결국 랜더링 될때마다 디펜던시 배열이 무의미 해진것
따라서 아래와 같이 메모이제이션을 해야한다.
const somefunction = useCallback(()=>{
console.log("어쩌고 저쩌고")
},[]);
useRef
ref는 컴포넌트의 전생의 주기에 사용이 가능하다.
useRef는
1. state와 비슷하게 저장공간으로 사용이 된다.
state의 변화 -> 렌더링 -> 컴포넌트 내부 변수들 초기화
ref의 변화 -> No 렌더링 -> 변수들의 값이 유지 됨
state의 변화 -> 렌더링 -> 그래도 ref의 값은 유지 됨
2. Dom요소에 접근이 가능하다.
자동으로 포커스 조정이 가능하다. ref를 사용하면 input요소에 자동으로 접근이 가능하다.
사용의 이점: 자주 상태가 변경되는 값은 ref로 관리를 하여 랜더링이 되지 않아도 상태가 변경될 수 있게 만들 수 있다. 즉, useRef Hook은 함수형 컴포넌트에서 ref를 쉽게 사용할 수 있게 만든다!
아래의 예시는 Dom요소에 쉽게 접근하는 방법에 대해서 다뤘당
const App = () => {
const inputRef = useRef();
useEffect(()=>{
inputRef.currnet.focus();
},[]);
const login = () =>{
alert(`환영합니다.`);
inputRef.currnet.focus();
};
return(
<div>
<input ref={inputRef} />
<button onClick={login}/>
</div>
)
}
'SW 정글사관학교 > 리액트' 카테고리의 다른 글
[리액트/recoil] - 상태관리 웨 쓰는건데 (0) | 2023.06.05 |
---|
댓글