React 18 - 성능 개선
26419 단어 javascriptreact
이 게시물에서는 성능 관련 기능에 대해 자세히 살펴보겠습니다.
useTransition
상태 업데이트의 우선 순위를 지정할 수 있는 동시성 개념의 일부입니다.
긴급한 상태 업데이트는 덜 긴급한(차단) 업데이트보다 우선 순위를 지정할 수 있습니다.
이를 사용하는 방법과 이 새로운 후크가 앱 성능을 향상시키는 방법은 찾을 수 있는 예제에서 배울 수 있습니다here.
이것은 우리의 예입니다. 간단합니다. 모달을 여는 버튼이 있고 모달 내에서 500개의 댓글 목록을 렌더링합니다.
500개의 댓글은 많지만 대부분의 기기에서 잘 작동합니다.
import { useState } from "react";
import Comments from "../components/Comments";
import Modal from "../components/Modal";
import data from "../data/index.json";
export default function Home() {
const [isOpen, setIsOpen] = useState(false);
const [comments, setComments] = useState([]);
return (
<div className="p-4">
<button
className="px-4 py-2 border-none rounded-sm bg-blue-800 text-white"
onClick={() => {
setIsOpen(true);
setComments(data);
}}
>
Toggle modal
</button>
<Modal
isOpen={isOpen}
onClose={() => {
setIsOpen(false);
setComments([]);
}}
>
<Comments comments={comments} />
</Modal>
</div>
);
}
그러나
Comment
구성 요소의 렌더링 속도를 늦추면 😈 상황이 더욱 흥미로워집니다.이를 달성하기 위해 백만 번 반복하는 루프
for
를 추가했습니다.const Comment = ({ name, email, body, className, onClick }: CommentProps) => {
const soooSloww = [];
for (let i = 0; i < 1000000; i++) {
soooSloww.push(i);
}
return (
<article className={className} onClick={onClick}>
<h3 className="font-semibold">{name}</h3>
<h4 className="text-gray-500 italic">{email}</h4>
<p>{body}</p>
</article>
);
};
이제 버튼을 클릭하여 모달을 열면 몇 초 동안 아무 일도 일어나지 않습니다.
이는 브라우저가 느린 500개
Comment
구성 요소를 렌더링하느라 바쁘기 때문입니다.얼마 후 모달과 주석이 렌더링됩니다.
사용자 관점에서 이것은 매우 나쁜 UX입니다.
그것을 개선하는 방법?
렌더링의 우선 순위를 지정할 수 있으며 이 예에서는 먼저 모달을 렌더링하고 그 주석을 렌더링하는 것이 더 중요합니다.
useTransition
후크는 전환이 아직 완료되지 않았다는 부울 플래그인 pending
와 덜 중요한 상태 업데이트를 실행하는 함수인 startTransition
두 변수를 반환합니다.const [pending, startTransition] = useTransition();
이제 우리의 예는 다음과 같습니다
export default function Home() {
const [isOpen, setIsOpen] = useState(false);
const [comments, setComments] = useState([]);
const [pending, startTransition] = useTransition();
return (
<div className="p-4">
<button
className="px-4 py-2 border-none rounded-sm bg-blue-800 text-white"
onClick={() => {
setIsOpen(true);
startTransition(() => {
setComments(data);
});
}}
>
Toggle modal
</button>
<Modal
isOpen={isOpen}
onClose={() => {
setIsOpen(false);
setComments([]);
}}
>
{pending ? "Loading..." : <Comments comments={comments} />}
</Modal>
</div>
);
}
버튼을 클릭하면 우선 순위가 더 높은 작업인 모달을 표시하도록 상태를 업데이트하고 React에 상태 업데이트가 우선 순위가 더 낮다는 것을 알려주는
startTransition
함수 내에서 주석 상태를 업데이트한다는 것을 알 수 있습니다.또한
pending
플래그를 사용하여 느린 댓글이 렌더링되는 동안 사용자에게 '로드 중...' 텍스트를 표시했습니다.이제 버튼을 클릭하면 다음과 같은 모달이 즉시 나타납니다.
훨씬 더 나은 사용자 경험! 😀
useDeferredValue
또한 이 후크는 React에 특정 상태 업데이트의 우선순위가 낮다고 알려줍니다.
그것은
useTransition
와 유사하며 솔직히 말해서 useDeferredValue
보다 useTransition
를 선호해야 하는 사용 사례가 무엇인지 잘 모르겠습니다. 아이디어가 있으면 의견에 알려주십시오. 👇이전 예제는 이제 다음과 같으며
pending
플래그가 없다는 점을 제외하면 유사하게 동작합니다.export default function UseDeferredValues() {
const [isOpen, setIsOpen] = useState(false);
const [comments, setComments] = useState([]);
const commentsToRender = useDeferredValue(comments);
return (
<div className="p-4">
<button
className="px-4 py-2 border-none rounded-sm bg-blue-800 text-white"
onClick={() => {
setIsOpen(true);
setComments(data);
}}
>
Toggle modal
</button>
<Modal
isOpen={isOpen}
onClose={() => {
setIsOpen(false);
setComments([]);
}}
>
<Comments comments={commentsToRender} />
</Modal>
</div>
);
}
자동 배치
React로 작업할 때 가능한 한 재렌더링을 적게 하는 것을 목표로 해야 합니다.
이제 React 18은 자동 일괄 처리를 통해 이를 달성할 수 있도록 도와줍니다.
이전 버전의 React는
onClick
또는 onChange
와 같은 React 이벤트 핸들러 내에서만 여러 상태 업데이트를 일괄 처리하여 여러 번의 재렌더링을 방지하고 성능을 향상시켰습니다.이제 React는 React 이벤트 핸들러, 약속, setTimeout, 기본 이벤트 핸들러 등에서 상태 업데이트를 일괄 처리합니다.
const AutomaticBatching = () => {
const [countOne, setCountOne] = useState(0);
const [countTwo, setCountTwo] = useState(0);
console.log("render");
const onClick = useCallback(() => {
setCountOne(countOne + 1);
setCountTwo(countTwo + 1);
}, [countOne, countTwo]);
useEffect(() => {
document.getElementById("native-event").addEventListener("click", onClick);
return () =>
document
.getElementById("native-event")
.removeEventListener("click", onClick);
}, [onClick]);
const onClickAsync = () => {
fetch("https://jsonplaceholder.typicode.com/todos/1").then(() => {
setCountOne(countOne + 1);
setCountTwo(countTwo + 1);
});
};
const onClickTimeout = () =>
setTimeout(() => {
setCountOne(countOne + 1);
setCountTwo(countTwo + 1);
}, 200);
return (
<div className="p-4">
<ul className="mb-8">
<li>Count one: {countOne}</li>
<li>Count two: {countTwo}</li>
</ul>
<Button onClick={onClick}>Batching in click event</Button>
<Button id="native-event" className="ml-4">
Batching in native click event
</Button>
<Button className="ml-4" onClick={onClickAsync}>
Batching in fetch
</Button>
<Button className="ml-4" onClick={onClickTimeout}>
Batching in timeout
</Button>
</div>
);
};
이 예에서는 모든 이벤트 핸들러에서 상태 변경이 두 번 있지만 다시 렌더링은 한 번만 있음을 알 수 있습니다. 각 이벤트에 대해 하나의 console.log가 있음을 알 수 있습니다.
향상된 서스펜스
Suspense
는 React.lazy
와 함께 작동하여 로드될 때까지 구성 요소 렌더링을 일시 중단하고 해당 시간 동안 대체를 렌더링합니다.const LazyComponent = lazy(() => import("../components/LazyComponent"));
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
이는 즉시 필요하지 않은 앱의 일부(예: 모달)를 초기 번들에 포함하지 않는 방식으로 성능을 향상시키는 좋은 방법입니다.
그러나
Suspense
는 새로운 기능이 아니라 이전 버전의 React에 존재했으며 새로운 기능은 이제 이전에는 없었던 서버 측 렌더링과 함께 작동한다는 것입니다.여기까지입니다. 새 버전의 React가 마음에 드시기 바랍니다. 😀
위의 모든 예에서 찾을 수 있습니다here.
Reference
이 문제에 관하여(React 18 - 성능 개선), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/markoarsenal/react-18-performance-improvements-26el텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)