Get React to re-use custom blocks on re-render
See original GitHub issueI’ve been stuck mostly all day on this issue and would really appreciate any pointers.
I’m trying to figure out how to modify draft-js so that it doesn’t re-render whole custom blocks, i.e. it reuses markup already there.
I’ve decided to use draft-js as the rendering engine for some forms I’m creating, I’ve got a custom block which is the text input you can see in the below screen capture. The text input’s value is derived from the custom block’s data: { text: 'custom value' }
attribute. I’ve made some custom code that applies a new editorState with an updated data.text
value when the user types in the input. This is all working great, however React always blats everything inside the <figure />
element and doesn’t re-use the markup that’s already there. Which causes the field to lose focus.
Screen capture:
I suspect it’s something to do with ‘DraftEditorContents.react.js’ file or the ‘DraftEditorBlock.react.js’ file. I’ve tried making sure the key properties are always unique but haven’t had any success.
Here’s the line that creates the custom component. The Element
variable is "figure"
and react is smart enough to reuse this, however it always creates new nodes for its children.
I’ve also tried commenting out the shouldComponentUpdate
methods in both those two files to see if handing control back to however React would handle it by default would help but it doesn’t make a difference.
Once again would really appreciate any help or pointers you might have. Thanks.
This is my code I use to update the editorState
content = content.setIn(['blockMap', key, 'data', 'value'], state['value'])
var newEditorState = EditorState.push(form['editorState'], content, 'change-block-data')
Issue Analytics
- State:
- Created 7 years ago
- Comments:7 (3 by maintainers)
@AlastairTaft I experienced the same issue, and I realized that I was generating a whole new ReactClass on each render, which, I think, is what your
props => ...
approach above is doing. Each time theBlockRendererFn
is executed by Draft, a new ReactClass is generated, and there’s no way for React to know that it’s the same as the one that was generated last time.I bet it’d work if you moved the definition for that component out of the
BlockRendererFn
.Using
<Component...>
directly works because the React class stays the same, even though you’re creating a new instance of that class (a new ReactElement). Since the class is the same, React can tell that you want to reuse the existing one.I figured out my issue, might help someone else.
My custom block renderer used to wrap the component in another component and merge in the props.
I’ve since swapped that to just using
I don’t like having to access all my custom properties through
this.props.blockProps
but at least it renders okay and gives me something to progress from.UPDATE: I created a BlockPropsDelegator class to use instead of an inline
props => <Component />
React seems to be able to reconcile this. So I guess the trick is React doesn’t reuse components when they are wrapped in aprops => <Component />
. I’ve used that trick a lot in the past but now I know to stay clear of it.