I'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')
have you tried to return editable as false in you blockReanderFn?
return {
component: yourComponent,
editable: false,
Thanks @mzbac, just gave that a go, but unfortunately it doesn't seem to make a difference.
@AlastairTaft seem you try do something similar like tex does in example of draft-js. you may can have look at
https://github.com/facebook/draft-js/tree/master/examples/tex
Thanks, that's a good pointer, I'll dig through that.
Hey @AlastairTaft,
Two quick points.
DraftModifier to perform updates on the ContentState. This will ensure that all edge cases are dealt with.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.
return {
component: props => <Component
{...props}
{...data}
onChange={(value) => onChange(contentBlock.key, value)}
/>,
editable: false,
}
I've since swapped that to just using
return {
component: Component,
editable: false,
props: {
...data,
onChange: (value) => onChange(contentBlock.key, value),
},
}
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 a props => <Component />. I've used that trick a lot in the past but now I know to stay clear of it.
@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 the BlockRendererFn 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.
Most helpful comment
@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 theBlockRendererFnis 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.