如何通过Entity Key替换DraftJS中的链接实体?
Let's break down what's going wrong with your replaceLink function and fix it step by step.
What's Wrong with Your Current Implementation
Your core issue is a misunderstanding of how replaceEntityData works:
- Incorrect use of
replaceEntityData: This method is meant to update the data properties of an existing entity, not replace the entity key itself. Passing{ entityKey }as the data object overwrites the link'surlandtextfields, which is why your table shows empty values after clicking "Replace link". - Muddled state update logic: You're creating a new entity, then trying to patch the state in conflicting ways (mixing
EditorState.setandEditorState.pushincorrectly).
Solution 1: Update the Existing Link Entity (Simpler)
Since your LINK entity is marked as MUTABLE, you can directly update its data without creating a new entity. This is the most efficient approach:
const replaceLink = ( link: string, text: string, editorState: EditorState, setEditorState: (editorState: EditorState) => void ): void => { const contentState = editorState.getCurrentContent(); const currentLinkKey = getCurrentLinkKey(editorState, contentState); if (!currentLinkKey) return; // Step 1: Update the existing link entity's data const contentWithUpdatedEntity = contentState.replaceEntityData( currentLinkKey, { url: link, text } ); // Step 2: Replace the selected text with the new link text (if needed) const selection = editorState.getSelection(); const finalContentState = Modifier.replaceText( contentWithUpdatedEntity, selection, text, editorState.getCurrentInlineStyle(), currentLinkKey ); // Step 3: Push the updated content state to the editor const newEditorState = EditorState.push( editorState, finalContentState, "update-link" ); setEditorState(newEditorState); };
Solution 2: Create a New Entity and Replace the Old One
If you need to create a fresh entity (e.g., for auditing or changing entity metadata), use this approach to swap out the entity key associated with the selected text:
const replaceLink = ( link: string, text: string, editorState: EditorState, setEditorState: (editorState: EditorState) => void ): void => { const contentState = editorState.getCurrentContent(); const selection = editorState.getSelection(); // Step 1: Create a new link entity const contentWithNewEntity = contentState.createEntity( "LINK", "MUTABLE", { url: link, text } ); const newEntityKey = contentWithNewEntity.getLastCreatedEntityKey(); // Step 2: Replace the selected text's entity with the new one (and update text) const updatedContent = Modifier.replaceText( contentWithNewEntity, selection, text, editorState.getCurrentInlineStyle(), newEntityKey ); // Step 3: Update the editor state const newEditorState = EditorState.push( editorState, updatedContent, "insert-characters" ); setEditorState(newEditorState); };
Bonus: Ensure Full Link Selection
To make sure the entire link is replaced even if the user only clicks part of it, add this helper function to expand the selection to the full link range:
const getFullLinkSelection = (editorState: EditorState): SelectionState => { const contentState = editorState.getCurrentContent(); const linkKey = getCurrentLinkKey(editorState); if (!linkKey) return editorState.getSelection(); const blockKey = editorState.getSelection().getStartKey(); const block = contentState.getBlockForKey(blockKey); let startOffset = 0; let endOffset = block.getLength(); // Find the full range of the link entity in the block block.findEntityRanges( (char) => char.getEntity() === linkKey, (start, end) => { startOffset = start; endOffset = end; } ); return new SelectionState({ anchorKey: blockKey, anchorOffset: startOffset, focusKey: blockKey, focusOffset: endOffset, }); };
Then use it in your replaceLink function by swapping editorState.getSelection() with getFullLinkSelection(editorState).
内容的提问来源于stack exchange,提问作者johannchopin

