[英]React speed up rendering of nested components
I'm trying to implement a syntax highlighter using React. 我正在尝试使用React来实现语法荧光笔。 The syntax highligher component itself is Redux independent, but Redux is still relevant.
语法highligher组件本身是Redux独立的,但是Redux仍然是相关的。
The highlighter takes 2 props 荧光笔需要2个道具
structure
- It's a 2d array with the id's of tokens to be rendered, split to lines, example: structure
-这是一个二维数组,其中包含要渲染的令牌ID,分为几行,例如:
const structure = [
[ // a line
"ryMtafN9b",
"r1WftTfEcZ",
"rkfftaMV5W"
],
[ // another line
"B1sGYTG4cZ",
"By3MYpzEq-"
],
...
]
tokens
- A mapping between token id and token, example: tokens
-令牌ID和令牌之间的映射,例如:
const tokens = {
"ryMtafN9b": {
"type": "LEFT_SQUARE_BRACKET",
"value": "[",
"id": "ryMtafN9b"
},
"r1WftTfEcZ": {
"type": "WHITESPACE",
"value": " ",
"id": "r1WftTfEcZ"
},
"rkfftaMV5W": {
"type": "LEFT_CURLY_BRACKET",
"value": "{",
"id": "rkfftaMV5W"
},
...
}
The rendering then happens like this (removed all irrelevant stuff): 然后,渲染就这样进行(删除了所有不相关的内容):
One token 一个令牌
class TokenElement extends PureComponent {
render() {
// return a <span> based on the token type, etc
}
}
One row (line) 一行(行)
class TokenRow extends PureComponent {
render() {
const { tokens } = this.props
return (<div>
{tokens.map((token) => <TokenElement token={token} key={token.id} />)}
</div>)
}
}
The actual highlighter component 实际的荧光笔组件
class JsonSyntaxHighlighter extends PureComponent {
render() {
const { tokens, structure } = this.props
return (<pre>
{
structure.map((line) => (<TokenRow tokens={line.map((tokenId) => tokens[tokenId])} />))
}
</pre>)
}
}
The problem The reason I'm implementing a custom syntax highlighter, is because I need to add custom decorations on token level based on data coming in async. 问题之所以我实现自定义语法荧光笔,是因为我需要基于异步传入的数据在令牌级别添加自定义修饰。 These updates coming in the form of extending each token in the
tokens
object, without mutations through a reducer (The whole highlighter component is rendered by a connected smart component). 这些更新以扩展
tokens
对象中的每个令牌的形式出现,而没有通过reducer进行更改(整个荧光笔组件由连接的智能组件呈现)。 Even though all the components are PureComponent
s the re-rendering of one single token takes a long time since: 即使所有组件都是
PureComponent
,单个令牌的重新渲染也需要很长时间,因为:
JsonSyntaxHighlighter
checks if needs to update - YES (since the tokens
object changed in it's props) JsonSyntaxHighlighter
检查是否需要更新- 是 (因为tokens
对象在道具中已更改) TokenRow
checks if needs to update - YES (since it's tokens
array has changed, because it's a result of a map
ping) TokenRow
检查是否需要更新- 是 (因为它的tokens
数组已更改,因为它是map
ping的结果) TokenElement
checks if needs to update MAYBE (since now I can rely on shouldComponentUpdate
properly). TokenElement
检查是否需要更新MAYBE (因为现在我可以正确地依赖shouldComponentUpdate
)。 Now when a lot's of these small updates arrive in a relatively small interval, the UI just blocks since a tons of re-renders are queued up. 现在,当许多这样的小更新以相对较小的间隔到达时,由于大量的重新提交排队,因此UI只是阻塞了。
Question Can I structure my data or my components better, so that frequent changes in individual token's state can trigger renders fast, without checking the whole tree? 问题我可以更好地构造数据或组件的结构,以便频繁地更改单个令牌的状态而无需检查整个树就可以快速触发渲染吗?
Facebook has a great article on exactly this topic. Facebook在这个主题上有一篇很棒的文章。
Short answer is to use React's shouldComponentUpdate
lifecycle method generously to specify when whole the component tree should avoid updating. 简短的答案是慷慨地使用React的
shouldComponentUpdate
生命周期方法来指定整个组件树何时应避免更新。 Here are a few examples on how to do that. 以下是一些有关如何执行此操作的示例。
I don't have proper code samples (it would be too much code to post here) but the way I ended up solving this is batching the plentiful store updates into chunks using Observable
s ( rxjs
, buffer
operator). 我没有合适的代码示例(在此处发布太多代码),但最终解决此问题的方法是使用
Observable
s( rxjs
, buffer
运算符)将大量存储更新分批处理。 This made the reducer code a bit more complex since state merges were not so natural, but now I have complete control over how frequently the store updates happen, and this implies control over how frequently render
s happen. 由于状态合并不是很自然的,这使化简代码变得更加复杂,但是现在我可以完全控制商店更新的发生频率,这意味着可以控制
render
频率。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.