store에서 객체를 통째로 불러오는 대신, 필요한 값들을 쪼개어서 useSelector로 선언해줌.
const number = useSelector(state => state.counter.**number**);
const diff = useSelector(state => state.counter.**diff**);
→ number 또는 diff 가 바뀌었을 때만 리렌더링됨.
shallowEqual은 react-redux에 내장되어있는 함수로, 객체 안의 가장 겉에 있는 값들을 비교해줌.
const { number, diff } = useSelector(
state => ({
number: state.counter.number,
diff: state.counter.diff
}),
shallowEqual
);
: useSelector 두번째 인자에 equality function을 직접 작성하여 추가
const result = useSelector(functionA, equalityFn)
참고자료
React 에서 useSelector 최적화 하는 3가지 방법.
컴포넌트를 React.memo()로 래핑시, 렌더링 결과를 Memoizing 하고 다음 렌더링이 일어날 때 props가 일치한다면, React는 Memoizing된 내용을 재사용함.
예시
import React from 'react';
const CreateUser = ({ **username, email, onChange, onCreate** }) => {
return (
<div>
<input
name="username"
placeholder="계정명"
onChange={onChange}
value={username}
/>
<input
name="email"
placeholder="이메일"
onChange={onChange}
value={email}
/>
<button onClick={onCreate}>등록</button>
</div>
);
};
export default **React.memo(CreateUser);**
참고 자료
사용방법을 제외하고는 React.memo와 매우 흡사함
React.memo가 component의 결과 값을 memoizing하여 불필요한 re-rendering을 관리한다면, useMemo
는 함수의 결과 값을 memoizing하여 불필요한 연산을 관리함.
예시
const computeExpensiveValue(a, b) = 비싼 함수 계산;
const memoizedValue = **useMemo(**() => computeExpensiveValue(a, b), **[a, b**]**);**
// SLOW
const sortedWords = ~~sortWords~~();
//FAST
const sortedWords = useMemo(**sortWords**, [words]);
useMemo
는 useCallback
은 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용const App =()=>{
//함수 선언
const onToggle = **useCallback**(id => {
setUsers(
users.map(user =>
user.id === id ? { ...user, active: !user.active } : user
)
);
}, [users]);
....
return (
//prop으로 함수를 pass down
<CreateUser onToggle={**onToggle**} />
)
}
주의점 : 메모제이션용 메모리가 추가로 필요하므로, 불필요한 props 비교 절약을 위해서 useCallback, useMemo, React.memo 는 컴포넌트의 성능을 실제로 개선할 수 있는 상황에서만 사용
👉 성능확인은 Dev tools Profiling 탭으로 꼭 확인!
: 부모 컴포넌트 바깥에 있는 DOM 노드로 자식을 렌더링할 수 있게 해주는 기능.
(UI 를 어디에 렌더링 시킬지 DOM 을 사전에 선택하여 부모 컴포넌트의 바깥에 렌더링 할 수 있게 해주는 기능)
ReactDOM.createPortal(**child-렌더링 대상**, **container**-**DOM 엘리먼트**)
존재 위치는 부모 바깥이지만! 모든 다른 면에서 일반적인 React 자식처럼 동작(ex. context, props, 이벤트 버블링)
→ why? DOM 트리 위치는 바뀌지만, portal은 여전히 React 트리에 존재하기 때문.
예시
모달
, 호버카드
, 툴팁
과 같은 경우에 주로 사용됨.
https://codepen.io/gaearon/pen/yzMaBd
예시
import PortalExample from "./Portal";
import React, { useRef } from "react";
function App() {
const modalRef = useRef();
const openModal = () => {
// 자식에서 정의한 함수를 trigger
modalRef.current.**openModal**();
};
return (
<div className="App">
<**PortalExample** **ref={modalRef}**>
<h1>Modal Header</h1>
<p> lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum </p>
</**PortalExample**>
<button onClick={openModal}>Open Portal Modal</button>
</div>
);
}
export default App;
import React, { useState, forwardRef, useImperativeHandle } from "react";
import ReactDOM from "react-dom"; //
//ref 부모로부터 전달받기 위해 두번째 인자로 ref를 넣어줌.
const PortalExample = **forwardRef**((props, ref) => {
const [display, setDisplay] = useState(true);
//useImperativeHandle을 통해 App.js(부모) 에서 아래 함수 사용가능
**useImperativeHandle**(ref, () => {
return {
openModal: () => open(),
close: () => close(),
};
});
//전달할 함수
const open = () => {
setDisplay(true);
};
const close = () => {
setDisplay(false);
};
return (
display &&
ReactDOM.**createPortal**(
<Portal>
<div className="modal-backdrop" onClick={close}></div>
<div className="modal-box">{props.children}</div>
</Portal>,
document.getElementById("modal-root")
)
);
});
const Portal = styled.div`
position: fixed;
....
.modal-backdrop {
position: fixed;
top: 0;
...
}
.modal-box {
position: relative;
top: 50%;
....
}
`;
export default PortalExample;
참고자료