Ben*_*ams 7 javascript performance typescript reactjs recharts
我有一个 Recharts 用例,我渲染了超过 20,000 个数据点,这导致了阻塞渲染:
(CodeSandbox 有一个小的脉冲动画,因此在创建新图表数据时更容易看到阻塞渲染。)
在使用开发工具衡量性能时,很明显,造成这种情况的原因不是浏览器painting或rendering活动,而是 Recharts 的scripting活动:
我绝不想在这里责怪 Recharts,20k 点很多,但有没有人知道是否有办法绕过阻塞渲染?
我尝试过的事情:
1.) 增量加载
增量加载更多数据(例如 2k + 2k + 2k + ... = 20k),这只会导致更多、更小的渲染阻塞时刻。
2.) 渲染前加载动画
在渲染组件中添加了一个小的布尔状态来跟踪“挂载”状态,它至少会在图表组件挂载时显示加载动画,因此用户不会等待空白页面/路由切换:
const [showLoading, setShowLoading] = useState<boolean>(true);
const { isLoading, data } = useXY() // remote data fetching
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
useEffect(() => {
setShowLoading(isLoading || !isMounted);
}, [isLoading, isMounted]);
...
if (showLoading) return <LoadingAnimation />
return <div>...chart...</div>
Run Code Online (Sandbox Code Playgroud)
图表 代码:(完整代码见CodeSandbox)
const [showLoading, setShowLoading] = useState<boolean>(true);
const { isLoading, data } = useXY() // remote data fetching
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
useEffect(() => {
setShowLoading(isLoading || !isMounted);
}, [isLoading, isMounted]);
...
if (showLoading) return <LoadingAnimation />
return <div>...chart...</div>
Run Code Online (Sandbox Code Playgroud)
您可以使用(当前处于实验阶段)React Concurrent Mode。在并发模式下,渲染是非阻塞的。
export default function App() {
// imagine data coming from an async request
const [data, setData] = useState<Data>(() => createData());
const [startTransition, isPending] = unstable_useTransition();
function handleNoneBlockingClick() {
startTransition(() => setData(createData()));
}
function handleBlockingClick() {
setData(createData());
}
return (
<div className="App">
<button onClick={handleNoneBlockingClick}>
(None blocking) Regenerate data
</button>
<button onClick={handleBlockingClick}>(Blocking) Regenerate data</button>
{isPending && <div>...pending</div>}
{data && (
<>
<p>
Number of data points to render:{" "}
{useMemo(
() =>
data.lines.reduce((acc, item) => {
return acc + item.data.length;
}, 0),
[data.lines]
) +
useMemo(
() =>
data.areas.reduce((acc, item) => {
return acc + item.data.length;
}, 0),
[data.areas]
)}
</p>
<Animation />
<Chart data={data} />
</>
)}
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,我使用新的 stable_useTransition 挂钩,并在单击按钮时启动Transition,以对图表数据进行无阻塞计算。
动画不是完美的 60fps,但网站仍然响应良好!
查看代码的此分支中的差异:
https://codesandbox.io/s/concurrent-mode-recharts-render-blocking-forked-m62kf?file=/src/App.tsx
| 归档时间: |
|
| 查看次数: |
656 次 |
| 最近记录: |