[React.js] 리액트의 useEffect 활용법 & 성능 최적화 방법
2021. 7. 19. 00:14ㆍWeb_Programming/React
💻 useEffect 활용법
❗ 의존성 배열은 잘못 입력 시, 버그로 이어질 수 있어 되도록 사용하지 않는 것을 권장
💡 useEffect 내에서 사용되는 값은 의존성배열에 추가해주어야 변경사항이 적용됨.
function Profile({ userId }) {
const [user, setUser] = useState();
useEffect(() => {
fetchUser(userId).then(data => setUser(data));
}, [userId]);
}
💡 마운트 시점에만 실행되기 원한 다면 별도의 훅으로 사용하면 더 직관적이라는 장점이 있습니다.
function Profile({ userId }) {
const [user, setUser] = useState();
useOnMounted(() => fetchUser(userId).then(data => setUser(data)))
}
💡 useEffect 내에서 async/await 함수 사용
useEffect는 항상 함수 를 반환해야하기 때문에 별도의 함수를 정의하여 사용합니다.
function Profile({ userId }) {
const [user, setUser] = useState();
async function fetchAndSetUser () {
const data = await fetchUser(userId);
setUser(data);
}
useEffect(() => {
fetchAndSetUser();
}, [fetchAndSetUser]);
return (...);
}
💡 의존성 배열 사용을 줄이기 위한 방법
- if문으로 호출 조절
function Profile({ userId }) {
const [user, setUser] = useState();
async function fetchAndSetUser() {
const data = await fetchUser(userId);
setUser(data);
}
useEffect(() => {
if(!user || user.id !== userId) {
fetchAndSetUser();
}
});
// ...
}
- 상태값 변경함수의 매개변수로 함수를 사용
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
function onClick() {
setCount(prev => prev + 1);
}
window.addEventListener('click', onClick);
return () => window.removeEventListener('click', onClick);
});
// ...
}
- useReducer 훅 사용
function Timer({ initialTotalSeconds }) {
const [state, dispatch] = useReducer(reducer, {
hour: initialTotalSeconds / 3600
minute: (initialTotalSeconds % 3600) / 60
second: initialTotalSeconds % 60
});
const { hour, minute, second } = state;
useEffect(() => {
const id = setInterval(dispatch, 1000);
return () => clearInterval(id);
});
//...
}
function reducer(state) {
const { hour, minute, second } = state;
if(second) {
return { ..state, second: second - 1 };
} else if(second) {
return { ..state, minute: minute - 1, second: 59 };
} else if(second) {
return { ..state, hour: hour - 1, minute: 59, second: 59 };
} else {
return state;
}
}
- userRef 훅 사용
function MyComponent({ onClick }) {
const onClickRef = useRef();
// concurrent mode를 위한 작성법
useEffect(() => {
onClickRef.current = onClick;
});
useEffect(() => {
window.addEventListener('click', () => {
onClickRef.current();
// ...
})
// ...
});
// ...
}
💻 렌더링 속도를 올리기 위한 성능 최적화 방법
리액트는 데이터+컴포넌트 함수로 화면을 그립니다.
여기서 대부분의 연산은 "컴포넌트 함수 실행과 가상돔"에서 발생합니다.
+가상돔
이전 돔과 비교하여 변경된 부분만 렌더링하기 위한 가상의 돔
💡 React.memo
리액트 memo함수는 속성값이 변경될 경우에만 렌더링 하도록 도와주는 함수입니다.
memo함수는 첫번째인자로 컴포넌트, 두번째 인자로 비교함수를 받습니다.
두번째 인자가 없을시, 얕은 비교 수행 함수가 실행됩니다.
👉 얕은 비교라도 속성값이 변경되지 않았다면 실제 돔에도 변경되지 않아 큰문제는 없습니다.
function MyComponent(props) {
// ...
}
function isEqual(prefProps, nextProps) {
// true 또는 false를 반환
}
React.memo(MyComponent, isEqual)
이전 속성값과 상태값에 대해 포스팅 했을때,
불변값이 속성값과 가변값 상태값을 말했었습니다.
여기서 상태값 또한 불변값으로 관리하는 것이 좋다고 말했던 이유가 나오는데요.
값을 이전과 비교할떄 ===연산자로 비교하기 위해 객체를 불변객체로 관리하는것이 좋기 때문입니다.
const state = {};
const newState = {};
state === {...state, ...{name: 'horong'}}; // false
💡 함수 속성값
❗ 속성값으로 함수를 자식에게 넘겨줄 시, React.memo를 사용하였다 할 지라도
함수는 부모가 렌더링 될 떄마다 새로 생성되기 때문에 자식 또한 다시 렌더링됩니다.
👉 useCallback 훅 사용으로 해결
function Parent() {
const [v1, setV1] = useState();
const onChangeCallback = useCallback(v => {
// ...
setV1(v);
}, [])
return <Child onChange={onChangeCallback}>
}
💡 객체 속성값
❗ 객체 또한 함수와 동일하게 매번 새로운 객체로 인식합니다.
👉 불변객체라면 분리하여 작성
function Parent() {
return <Child data={DATA}>
}
const DATA = [1, 2, 3];
👉 가변객체라면 useMemo 훅 사용 ( :필요할 때만 변경)
function Parent() {
const [maxValue, setMaxValue] = useState(0);
const data = useMemo(() => DATA.filter(e => e<=maxValue), [
maxValue
]);
return <Child data={data}>
}
const DATA = [1, 2, 3];
'Web_Programming > React' 카테고리의 다른 글
[React.js]리액트 react-redux, reselect라이브러리 (0) | 2021.07.30 |
---|---|
[React.js] 리덕스(액션,미들웨어, 리듀서, 스토어) (0) | 2021.07.21 |
[React.js]리액트 타입선언, 조건부 렌더링, 컴포넌트 재사용성 (0) | 2021.07.16 |
[React.js]리액트 훅 규칙, Context API, 내장 훅 (0) | 2021.07.13 |
[React.js]리액트의 가상돔, 리액트 훅 기초 (0) | 2021.07.11 |