question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Get React to re-use custom blocks on re-render

See original GitHub issue

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: 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. custom block creation screenshot

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:closed
  • Created 7 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
mrmurphycommented, Jan 27, 2017

@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.

2reactions
AlastairTaftcommented, Sep 14, 2016

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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Just Say No to Excessive Re-Rendering in React - GrapeCity
In this article, we will address instances of excessive re-rendering in React applications and demonstrate how to avoid them.
Read more >
How can I prevent re-render after state changed in React ...
To prevent re-rendering of reusable component while changing other states, We can use React.memo()
Read more >
How To Create Custom Components in React - DigitalOcean
Custom components are independent pieces of functionality that you can reuse in your code, and are the building blocks of all applications ...
Read more >
Recoil in action: Building a reusable code block component
Recoil is a lightweight state management library for React. ... This helps us build our custom code blocks with syntax highlights ...
Read more >
Manipulating the DOM with Refs - React Docs
React automatically updates the DOM to match your render output, so your components won't often need to manipulate it. However, sometimes you might...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found