由于装饰器过多,随着内容的增加,Draft js Editor 变慢了
Draft js Editor gets slower as the content increases due to having many decorators
所以我的 draft-js 编辑器变得非常慢(hacky)我插入的内容越多(在大约 20 个装饰器替换之后)。我猜这种行为是由于装饰器使用正则表达式检查整个编辑器内容,并在每次状态更改时用表情符号组件替换匹配项。我还为正则表达式找到的每个匹配项创建实体,我通过使用编辑器状态作为道具装饰组件来做到这一点。有没有办法让它更快?
这是我的装饰器:
{
strategy: emojiStrategy,
component: decorateComponentWithProps(RenderEmoji, {
getEditorState: this.getEditorState,
setEditorState: this.onChange
})
}
这是我的表情符号策略:
function emojiRegexF(regex, contentBlock, callback, contentState) {
const text = contentBlock.getText();
let matchArr, start;
while ((matchArr = regex.exec(text)) !== null) {
start = matchArr.index;
callback(start, start + matchArr[0].length);
}
}
function emojiStrategy(contentBlock, callback, contentState) {
emojiRegexF(EMOJI_REGEX, contentBlock, callback, contentState);
}
这是我的 RenderEmoji 组件:
const RenderEmoji = props => {
const contentBlock = props.children[0].props.block;
const emojiKey = contentBlock.getEntityAt(props.children[0].props.start);
const emojiShortName = props.decoratedText;
if (!emojiKey) {
setEntity(props, emojiShortName);
}
return (
<Emoji emoji={emojiShortName} set="emojione" size={24}>
{props.children}
</Emoji>
);
};
这里是我的 setEntity 函数,它设置匹配的实体:
function setEntity(props, emojiShortName) {
const editorState = props.getEditorState();
const contentstate = editorState.getCurrentContent();
const contentStateWithEntity = contentstate.createEntity(
"emoji",
"IMMUTABLE",
{
emojiUnicode: emojiShortName
}
);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const oldSelectionState = editorState.getSelection();
const selectionState = oldSelectionState.merge({
focusOffset: props.children[0].props.start + props.decoratedText.length,
anchorOffset: props.children[0].props.start
});
const newContentState = Modifier.applyEntity(
contentstate,
selectionState,
entityKey
);
const withBlank = Modifier.replaceText(
newContentState,
selectionState,
emojiShortName + " ",
null,
entityKey
);
const newEditorState = EditorState.push(
editorState,
withBlank,
"apply-entity"
);
props.setEditorState(newEditorState);
}
有什么方法可以优化它吗?谢谢
我不确定这是否是任何实际性能问题的根源,但有两件事看起来很有趣:
- 通过正则表达式匹配表情符号装饰器,即使您正在为它们创建实体。
- 在装饰器渲染期间更改编辑器状态(通过
setEntity
)。渲染函数 should be pure.
我想你会进行这种类型的处理,因为可能会通过复制粘贴或某种原生表情符号选择器插入表情符号。更好的方法是:
- 使用
setEntity
逻辑为表情符号插入实体作为 onChange
的一部分 – 在内容保存和最终呈现之前。
- 使用仅基于实体的装饰器策略,例如:
const emojiStrategy = (contentBlock, callback, contentState) => {
contentBlock.findEntityRanges(character => {
const entityKey = character.getEntity();
return (
entityKey !== null &&
contentState.getEntity(entityKey).getType() === 'emoji'
);
}, callback);
};
那么您的装饰器组件将不需要在渲染期间更新编辑器状态。您也可能不再需要使用 decorateComponentWithProps
。
现在回到性能 - 要确定如何改进性能,最好的方法是 profile your app。您将能够准确判断出在击键过程中渲染哪些内容需要时间,然后追踪问题所在。
所以我的 draft-js 编辑器变得非常慢(hacky)我插入的内容越多(在大约 20 个装饰器替换之后)。我猜这种行为是由于装饰器使用正则表达式检查整个编辑器内容,并在每次状态更改时用表情符号组件替换匹配项。我还为正则表达式找到的每个匹配项创建实体,我通过使用编辑器状态作为道具装饰组件来做到这一点。有没有办法让它更快? 这是我的装饰器:
{
strategy: emojiStrategy,
component: decorateComponentWithProps(RenderEmoji, {
getEditorState: this.getEditorState,
setEditorState: this.onChange
})
}
这是我的表情符号策略:
function emojiRegexF(regex, contentBlock, callback, contentState) {
const text = contentBlock.getText();
let matchArr, start;
while ((matchArr = regex.exec(text)) !== null) {
start = matchArr.index;
callback(start, start + matchArr[0].length);
}
}
function emojiStrategy(contentBlock, callback, contentState) {
emojiRegexF(EMOJI_REGEX, contentBlock, callback, contentState);
}
这是我的 RenderEmoji 组件:
const RenderEmoji = props => {
const contentBlock = props.children[0].props.block;
const emojiKey = contentBlock.getEntityAt(props.children[0].props.start);
const emojiShortName = props.decoratedText;
if (!emojiKey) {
setEntity(props, emojiShortName);
}
return (
<Emoji emoji={emojiShortName} set="emojione" size={24}>
{props.children}
</Emoji>
);
};
这里是我的 setEntity 函数,它设置匹配的实体:
function setEntity(props, emojiShortName) {
const editorState = props.getEditorState();
const contentstate = editorState.getCurrentContent();
const contentStateWithEntity = contentstate.createEntity(
"emoji",
"IMMUTABLE",
{
emojiUnicode: emojiShortName
}
);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const oldSelectionState = editorState.getSelection();
const selectionState = oldSelectionState.merge({
focusOffset: props.children[0].props.start + props.decoratedText.length,
anchorOffset: props.children[0].props.start
});
const newContentState = Modifier.applyEntity(
contentstate,
selectionState,
entityKey
);
const withBlank = Modifier.replaceText(
newContentState,
selectionState,
emojiShortName + " ",
null,
entityKey
);
const newEditorState = EditorState.push(
editorState,
withBlank,
"apply-entity"
);
props.setEditorState(newEditorState);
}
有什么方法可以优化它吗?谢谢
我不确定这是否是任何实际性能问题的根源,但有两件事看起来很有趣:
- 通过正则表达式匹配表情符号装饰器,即使您正在为它们创建实体。
- 在装饰器渲染期间更改编辑器状态(通过
setEntity
)。渲染函数 should be pure.
我想你会进行这种类型的处理,因为可能会通过复制粘贴或某种原生表情符号选择器插入表情符号。更好的方法是:
- 使用
setEntity
逻辑为表情符号插入实体作为onChange
的一部分 – 在内容保存和最终呈现之前。 - 使用仅基于实体的装饰器策略,例如:
const emojiStrategy = (contentBlock, callback, contentState) => {
contentBlock.findEntityRanges(character => {
const entityKey = character.getEntity();
return (
entityKey !== null &&
contentState.getEntity(entityKey).getType() === 'emoji'
);
}, callback);
};
那么您的装饰器组件将不需要在渲染期间更新编辑器状态。您也可能不再需要使用 decorateComponentWithProps
。
现在回到性能 - 要确定如何改进性能,最好的方法是 profile your app。您将能够准确判断出在击键过程中渲染哪些内容需要时间,然后追踪问题所在。