惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
C
Cybersecurity and Infrastructure Security Agency CISA
N
News and Events Feed by Topic
C
Cisco Blogs
Cisco Talos Blog
Cisco Talos Blog
A
Arctic Wolf
Scott Helme
Scott Helme
P
Palo Alto Networks Blog
S
Schneier on Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Tor Project blog
量子位
G
Google Developers Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
B
Blog RSS Feed
NISL@THU
NISL@THU
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
AWS News Blog
AWS News Blog
爱范儿
爱范儿
Last Week in AI
Last Week in AI
Y
Y Combinator Blog
L
LINUX DO - 最新话题
Security Archives - TechRepublic
Security Archives - TechRepublic
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Secure Thoughts
Cloudbric
Cloudbric
aimingoo的专栏
aimingoo的专栏
L
Lohrmann on Cybersecurity
TaoSecurity Blog
TaoSecurity Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Hacker News: Ask HN
Hacker News: Ask HN
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
有赞技术团队
有赞技术团队
S
Security @ Cisco Blogs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cyber Attacks, Cyber Crime and Cyber Security
G
GRAHAM CLULEY
P
Proofpoint News Feed
V
V2EX
Martin Fowler
Martin Fowler
C
CERT Recently Published Vulnerability Notes
Attack and Defense Labs
Attack and Defense Labs
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Cloudflare Blog
SecWiki News
SecWiki News
罗磊的独立博客
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
小众软件
小众软件
The Last Watchdog
The Last Watchdog

ddadaal.me

fork subgen实现纯本地AI视频字幕生成和翻译 - ddadaal.me 把nanobot关进Docker后,如何同时保留浏览器可视化与自动化 - ddadaal.me 可划分显存 != 统一内存:AI Max+ 395 64G AI推理性能 2025年总结 - ddadaal.me 14寸16核32线程:搭载AMD AI Max+ 395的HP战99 Ultra使用感受 Node是并发性能的绊脚石吗?测试Express服务器的基准并发能力 - ddadaal.me 用大模型总结文章:效果很好,但是玄学 - ddadaal.me 2024年总结 - ddadaal.me 在西雅图,给生活换个环境 - ddadaal.me 从调库到翻源代码:给wakapi增加SQL Server支持 - ddadaal.me 增加自制博客点击量统计 - ddadaal.me 博客集成AI文章总结功能 - ddadaal.me 2023年总结 - ddadaal.me 博客的发展2:重写,重生 - ddadaal.me 2022年总结 - ddadaal.me 2021年总结 - ddadaal.me 我的第一个真实项目:总结和经验 - ddadaal.me 一次生产环境的文件丢失事故:复盘和教训 - ddadaal.me react-typed-i18n: 使用Template Literal Types实现强类型的i18n - ddadaal.me wslg初体验:最佳Linux发行版? - ddadaal.me 借助Docker,把VPN当作HTTP代理来用 - ddadaal.me 2020年总结 - ddadaal.me 美好的回忆和未知的未来:写在研究生开学前 - ddadaal.me 使用X11 Forwarding在WSL 2中运行GUI程序 - ddadaal.me 在小手机已经消失的时代,我选择了Galaxy S20 - ddadaal.me 使用PowerShell脚本让UWP应用使用localhost上的系统代理 - ddadaal.me 安装Arch Linux并使用N卡玩Steam游戏 - ddadaal.me 可靠性、辅助功能和多屏协同:我对智能手表的体验和看法 - ddadaal.me 从VSCode到Vim到……两个都用? - ddadaal.me 2019年总结 - ddadaal.me 入手4K显示器:LG 27UL550 - ddadaal.me 暗色模式上线 - ddadaal.me 修复gatsby-transformer-remark插件中文词数统计错误问题 - ddadaal.me 折腾Linux: 从实体机到Win10 - ddadaal.me 从viccrubs改名为ddadaal - ddadaal.me 博客的发展一:RSS,国内托管…… - ddadaal.me 2016至2019,和南京大学微软学生俱乐部一起成长 - ddadaal.me 北大信科 | 上交软院 | 南大软院夏令营经历 使用MVC、MVP、MVVM和FRP实现Android局域网群聊应用 - ddadaal.me 2019年春微软实习面试经验 - ddadaal.me Strongly Typed i18n with TypeScript A Kotlin DI Framework in 50 Lines and Thoughts on Kotlin 7天Hackathon,Web前端极速入门指南 - ddadaal.me An Infinite Loop Caused by Updating a Map during Iteration Simstate and Why - ddadaal.me 2018年总结 - ddadaal.me MSRA DKI组前端面经 - ddadaal.me Safety/Security and Extensibility/Scalability in Software System Design and Architecture 微软听听文档体验报告 - ddadaal.me 正则语法分析器和LALR(1)词法分析器 - ddadaal.me 新博客正式上线 - ddadaal.me 写代码要动脑子! - ddadaal.me 2017年总结 - ddadaal.me Python语言实现的符合本福特定律的十进制固定长度随机数发生器 - ddadaal.me 院自建GitLab CI配置实录 - ddadaal.me C++测例查看器 - ddadaal.me C++插件在VS2017上无法使用的分析 - ddadaal.me
A React Form Component Performance Optimization with Profiler
2019-10-13 · via ddadaal.me

✨AI全文摘要

DeepSeek R1DeepSeek R1 8B

A developer addressed severe performance issues in a React form, where input lagged significantly, especially when entering sequential keystrokes. Initially suspecting validations or form-wide re-renders, profiling with React DevTools revealed a Dropdown component (Semantic-UI) rendering 400+ options as the culprit. Each keystroke triggered re-renders, generating new option instances. The uncontrolled Dropdown was extracted into a PureComponent, memoizing options to prevent redundant renders. This reduced per-input render time from ~400ms to ~22ms, eliminating lag. The solution highlighted the importance of profiling to identify bottlenecks, controlled re-renders via memoization, and optimizing third-party components in large-scale React applications to maintain responsiveness.

Azure AI部署的DeepSeek-R1模型推理

Note: This code is from an internal project. Measurements apply to protect confidential information, but the problem and methods mentioned in the article are universal and not limited to specific projects.

The Problem

I was working on a form that had very poor performance. To be specific, at every key stroke, the form responded pretty slowly. What's worse, the component and the whole website became completely unresponsive for seconds if several keys were stroked sequentially (like input a long number), which was, unfortunately, the normal use case for this field.

bad performance, especially for the first input field
bad performance, especially for the first input field

Investigation

Validations?

From the gif provided above, you may find some details that are worth taking notice of:

  • The first field had the worse performance,
  • The first field had some kinds of input validation (loading indicator when the first inputs were registered),
  • The field below the first field had better performance than the first one, and it had no validation.

Hmm...It looks like the validation might be the cause.

However, the validation process was merely some format check, and a request which would be cancelled if next key stroke had come before it completed. It did increase the delay of input, but should not be so significant.

Re-renders of the Whole Form?

The Challenge of Forms in React

The re-render of the whole form at every input might be the problem as well.

React has been known as not good at implementing forms because of its famous unidirectional data flow.

Source: https://gist.github.com/alexmingoia/4db967e5aeb31d84847c. See this page to get yourself familiarized if you haven't already.
Source: https://gist.github.com/alexmingoia/4db967e5aeb31d84847c. See this page to get yourself familiarized if you haven't already.

Unidirectional data flow simplifies the data flow and fits seeminglessly with the concept of React. However, since each update to the state will trigger the component to re-render, it might impact the performance of the app.

Form is one of such cases, because a form consists of multiple input fields, and each input to any one of them would update the state, and re-render the whole form and every other fields. Therefore, writing forms in React has always a challenge.

Complicated Form

Looking at the code, the form was implemented in a very React way: the form contained all the fields, and handled every onChange event for each input fields.

part of fields
part of fields

The form was complicated with dozens of fields, several sync/async and cross-field validations, dynamic placeholders and some unnecessary duplicate calculations (which could be improved with constants and cache).

It seemed pretty evident that the re-renders and the complicated calculations during the render were the cause to the problem.

No Easy Solutions

Having found the reason, what's left was to find a solution. However, the reason that form implementation is called a challenge in React is that it can not be solved easily. There are lots of React form library from the community (like react-form, formik) trying to solve the form as a whole by providing a complete solution to some common form challenges, including input management, async validations, and submission. They may be viable for many users and should be considered if you are having trouble building a form in your project, but I couldn't adopt them in this project because:

  • hiding complexities usually means introducing other complexities
    • for example, when using the libraries, more problems are introduced, like less flexibilities, less understandable code, interop with UI libraries and the cost of learning and adopting a new set of APIs.
  • The code is involved with several internal concepts and conventions, which I am not familiar enough. As a result, I don't have the confidence to rewrite the logic correctly in a short time;
  • introducing a new library into this project is hard, for it is a internal project that has over 200K lines of TypeScript code, hundreds of authors and users, so the review for this project is strict.

Maybe Not Re-renders?

Besides, my experiences told me that it was possibly not the re-renders that was to blame, since the updates of the form should not be so costly that would result in such a significant delay.

I have encountered situations where even a whole page re-rendered at every interaction, but React and modern JavaScript engines is more than capable to drive it smoothly without even a stutter. This form had several fields to be re-rendered at every input, but when taking the whole page into consideration, the number of re-renders inside this page was negligible.

Profiling, Profiling, Profiling

After wasting days on brainstorming the source of problem, I decided to diagnose the issue in a scientific way -- profiling.

React's official devtool of Chrome has a built-in profiling tool. By recoding a sequence of user interactions, profiler can provide performance metrics on each commit during the record, like what components are re-rendered, how many time they take to re-render, with which the developer can locate the components that have biggest impact to the performance, and optimize them accordingly.

Start the recoding, repeat the operations of the gif above, and I had the following result:

Ranked chart
Ranked chart
Flamegraph chart
Flamegraph chart

The first chart (ranked chart) showed the time to re-render for each component that had re-rendered on this commit. The second chart (flamegraph chart) shoed the re-rendered components hierarchically: that is, the time to render the component itself, and each of its children.

As you could see, a Dropdown component took a significant time to re-render. In fact, all the graphes on all the last 10 commits had led me to the same component. By following the hierarchy provided by the flamegraph, it didn't take long to locate the component, which was the dropdown on the right side of the first field with slow responsiveness, and implemented as follows:

The dropdown
The dropdown

It looked like a normal dropdown with the exception of a duplicate calculations: generating an options array at every render. Providing different instances at every render is a common source of performance problem in React, because it signals React that the props have changed and a re-render is required, even the objects between renders are deep equal. The solution is straightforward: instead of generating a different instance each time, provide a constant or a class field that only changes when it is modified.

But unfortunately, in this case, after replacing the call to this.generateDropdown to a constant, the problem persisted.

Large Quantity of Options

The source of options of the dropdown came from a network request that was initiated when the page loaded. Another clue that I found during investigation was that when network errors happened, the input became very responsive, at which time the dropdown had no option. And after several intentional experiments, I found the correspondance between options and performance to be true (no option -> good performance, had options -> bad performace).

I was just a maintainer of the component, not the original authors, so I didn't take notice of the contents of dropdown during my previous investigation. Now, according to the correspondance, I checked out the options of the dropdown, only to find it had over 400 options.

>400 options
>400 options

Rendering so many options at each render would definitely impact performance pretty hard, unless the component had thought of it and selectively re-rendered only the changed part.

This project used React Wrapper of Semantic-UI which was a famous component library and open source. By diving into the source code, I found that the dropdown did re-render every options every time without any memoing or caching.

https://github.com/Semantic-Org/Semantic-UI-React/blob/master/src/modules/Dropdown/Dropdown.js#L1275

// omitted
renderOptions = () => {
  // omitted
  return _.map(options, (opt, i) =>
    DropdownItem.create({
      active: isActive(opt.value),
      onClick: this.handleItemClick,
      selected: selectedIndex === i,
      ...opt,
      key: getKeyOrValue(opt.key, opt.value),
      // Needed for handling click events on disabled items
      style: { ...opt.style, pointerEvents: 'all' },
    }),
  )
}
 
renderMenu = () => {
  // omitted
  return (
    <DropdownMenu {...ariaOptions} direction={direction} open={open}>
      {DropdownHeader.create(header, { autoGenerateKey: false })}
      {this.renderOptions()}
    </DropdownMenu>
  )
}
 
render() {
  // omitted
  return (
    // omitted
    {this.renderMenu()}
    // omitted
  )
}

Solution

In this case, the options didn't update anymore after the request had completed. Therefore, there was no need to update and re-render the options every time the component had changed.

To stop the re-render, I extracted the dropdown out into a separate component, passed the options as a prop, and most importantly, made it a PureComponent which only re-rendered itself when the props had changed.

The dropdown was used in a uncontrolled way -- that is, not managing its value by the DOM instead of as a state of React component by not passing value to the input DOM field. I had to admit it was not the React way, but here, not passing value to it meant that the component would never update, which was exactly what I wanted.

Optimized code
Optimized code

The optimization worked like a charm: the render time of the whole form for each input had reduced from ~400ms to ~22ms, and there was no any unresponsiveness and delay at every key stroke.

After
After

Verdict

Form is React is indeed a challenge. Without careful designing and implementation, problems may occur at any time, anywhere.

The issue here was ultimately the re-renders, but not the form I originally thought of, but the dropdown with large number of options. It is important to app performance to understand React update strategy and control the component update with lifecycle functions, property hook usage, memoing and caching, especially when the the number of component to render is too large.

The profiler was the key to finding the component to blame by providing the data of time to re-render for each component. Therefore, when a performance issue is detected, stop wasting guessing which compoenent causes it, and let profiler take you straight to it.