在 DraftJS 中执行异步装饰?
Perform Asynchronous Decorations in DraftJS?
我正在尝试在所见即所得编辑器中执行实时命名实体识别突出显示,这需要我在每次击键之间向我的后端发出请求。
在 ProseMirror 上花了大约一个星期后,我放弃了它并决定尝试 DraftJS。我搜索了存储库和文档,但没有找到任何使用 Decorations
的异步示例。 (有一些 Entities
的示例,但它们似乎不适合我的问题。)
这是我要解决的 stripped down Codepen。
归结为我想做这样的事情:
const handleStrategy = (contentBlock, callback, contentState) => {
const text = contentBlock.getText();
let matchArr, start;
while ((matchArr = properNouns.exec(text)) !== null) {
start = matchArr.index;
setTimeout(() => {
// THROWS ERROR: Cannot read property '0' of null
callback(start, start + matchArr[0].length);
}, 200) // to simulate API request
}
};
我希望它在超时解决后异步调用回调,但 matchArr
是空的,这让我很困惑。
感谢任何帮助!
好的,一个可能的解决方案,一个例子,简单的版本(可能不是 100% 固体):
- 写一个函数获取编辑器的字符串,将其发送到服务器,并解析从服务器获取的数据,你需要弄清楚发送整个编辑器字符串还是只发送一个单词
getServerResult = data => new Promise((resolve, reject) => {
...
fetch(link, {
method: 'POST',
headers: {
...
},
// figure what to send here
body: this.state.editorState.getCurrentContent().getPlainText(),
})
.then(res => resolve(res))
.catch(reject);
});
- 确定何时调用 getServerResult 函数(即何时将字符串发送到服务器并获取实体数据),据我从您的评论中了解到,当用户按下空格键时,将之前的单词发送到服务器,这可以完成通过 draftjs Key Bindings or react SyntheticEvent。您将需要处理用户连续多次按下空格键的情况。
function myKeyBindingFn(e: SyntheticKeyboardEvent): string {
if (e.keyCode === 32) {
return 'send-server';
}
return getDefaultKeyBinding(e);
}
async handleKeyCommand(command: string): DraftHandleValue {
if (command === 'send-server') {
// you need to manually add a space char to the editorState
// and get result from server
...
// entity data get from server
const result = await getServerResult()
return 'handled';
}
return 'not-handled';
}
- 使用 ContentState 添加从服务器获取的实体数据到特定单词。createEntity()
async handleKeyCommand(command: string): DraftHandleValue {
if (command === 'send-server') {
// you need to manually add a space char to the editorState
// and get result from server
...
// entity data get from server
const result = await getServerResult()
const newContentState = ContentState.createEntity(
type: 'string',
mutability: ...
data: result
)
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
// you need to figure out the selectionState, selectionState mean add
// the entity data to where
const contentStateWithEntity = Modifier.applyEntity(
newContentState,
selectionState,
entityKey
);
// create a new EditorState and use this.setState()
const newEditorState = EditorState.push(
...
contentState: contentStateWithEntity
)
this.setState({
editorState: newEditorState
})
return 'handled';
}
return 'not-handled';
}
- 创建不同的装饰器来查找具有特定实体数据的单词,以及 return 不同的样式或您需要的任何内容 return
...
const compositeDecorator = new CompositeDecorator([
strategy: findSubjStrategy,
component: HandleSubjSpan,
])
function findSubjStrategy(contentBlock, callback, contentState) {
// search whole editor content find words with subj entity data
// if the word's entity data === 'Subj'
// pass the start index & end index of the word to callback
...
if(...) {
...
callback(startIndex, endIndex);
}
}
// this function handle what if findSubjStrategy() find any word with subj
// entity data
const HandleSubjSpan = (props) => {
// if the word with subj entity data, it font color become red
return <span {...props} style={{ color: 'red' }}>{props.children}</span>;
};
我正在尝试在所见即所得编辑器中执行实时命名实体识别突出显示,这需要我在每次击键之间向我的后端发出请求。
在 ProseMirror 上花了大约一个星期后,我放弃了它并决定尝试 DraftJS。我搜索了存储库和文档,但没有找到任何使用 Decorations
的异步示例。 (有一些 Entities
的示例,但它们似乎不适合我的问题。)
这是我要解决的 stripped down Codepen。
归结为我想做这样的事情:
const handleStrategy = (contentBlock, callback, contentState) => {
const text = contentBlock.getText();
let matchArr, start;
while ((matchArr = properNouns.exec(text)) !== null) {
start = matchArr.index;
setTimeout(() => {
// THROWS ERROR: Cannot read property '0' of null
callback(start, start + matchArr[0].length);
}, 200) // to simulate API request
}
};
我希望它在超时解决后异步调用回调,但 matchArr
是空的,这让我很困惑。
感谢任何帮助!
好的,一个可能的解决方案,一个例子,简单的版本(可能不是 100% 固体):
- 写一个函数获取编辑器的字符串,将其发送到服务器,并解析从服务器获取的数据,你需要弄清楚发送整个编辑器字符串还是只发送一个单词
getServerResult = data => new Promise((resolve, reject) => {
...
fetch(link, {
method: 'POST',
headers: {
...
},
// figure what to send here
body: this.state.editorState.getCurrentContent().getPlainText(),
})
.then(res => resolve(res))
.catch(reject);
});
- 确定何时调用 getServerResult 函数(即何时将字符串发送到服务器并获取实体数据),据我从您的评论中了解到,当用户按下空格键时,将之前的单词发送到服务器,这可以完成通过 draftjs Key Bindings or react SyntheticEvent。您将需要处理用户连续多次按下空格键的情况。
function myKeyBindingFn(e: SyntheticKeyboardEvent): string {
if (e.keyCode === 32) {
return 'send-server';
}
return getDefaultKeyBinding(e);
}
async handleKeyCommand(command: string): DraftHandleValue {
if (command === 'send-server') {
// you need to manually add a space char to the editorState
// and get result from server
...
// entity data get from server
const result = await getServerResult()
return 'handled';
}
return 'not-handled';
}
- 使用 ContentState 添加从服务器获取的实体数据到特定单词。createEntity()
async handleKeyCommand(command: string): DraftHandleValue {
if (command === 'send-server') {
// you need to manually add a space char to the editorState
// and get result from server
...
// entity data get from server
const result = await getServerResult()
const newContentState = ContentState.createEntity(
type: 'string',
mutability: ...
data: result
)
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
// you need to figure out the selectionState, selectionState mean add
// the entity data to where
const contentStateWithEntity = Modifier.applyEntity(
newContentState,
selectionState,
entityKey
);
// create a new EditorState and use this.setState()
const newEditorState = EditorState.push(
...
contentState: contentStateWithEntity
)
this.setState({
editorState: newEditorState
})
return 'handled';
}
return 'not-handled';
}
- 创建不同的装饰器来查找具有特定实体数据的单词,以及 return 不同的样式或您需要的任何内容 return
...
const compositeDecorator = new CompositeDecorator([
strategy: findSubjStrategy,
component: HandleSubjSpan,
])
function findSubjStrategy(contentBlock, callback, contentState) {
// search whole editor content find words with subj entity data
// if the word's entity data === 'Subj'
// pass the start index & end index of the word to callback
...
if(...) {
...
callback(startIndex, endIndex);
}
}
// this function handle what if findSubjStrategy() find any word with subj
// entity data
const HandleSubjSpan = (props) => {
// if the word with subj entity data, it font color become red
return <span {...props} style={{ color: 'red' }}>{props.children}</span>;
};