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.

Proposal for Solution to Force Rerender/Selective Render of Nodes

See original GitHub issue

Issue

One issue I find appearing in multiple use cases is how to have editor state outside the nodes force rerendering of nodes.

Here are two use cases that can’t be handled elegantly right now:

  • Editor has an editing mode: For example, the editor has readOnly=false but that doesn’t mean we are editing right now. When the user clicks in the editor, we turn on editing mode. When you are in editing mode, the image blocks, for example, might show a “delete” button. This “delete” button should not show when you aren’t editing.

  • Highlight blocks: We want to highlight blocks depending on the block keys in an Array. highlightedBlocks=['abcde', 'fghij']. The list of highlighted blocks is an Array outside of the nodes. If the highlighted blocks change, the editor doesn’t know and therefore doesn’t change the rendering of the highlighted nodes.

One issue that was solved in another manner is the re-rendering problem when switching both from and to readOnly mode. My proposal will also discuss an alternate solution that can encompass readOnly mode as well.

https://github.com/ianstormtaylor/slate/pull/544

Proposal

I feel like a bad solution would be to continue to change shouldNodeComponentUpdate and keep passing through new values whenever new use cases appear. This is what was done to solve the readOnly problem.

My proposed solution is to pass in one new value through which is the value object itself. The value object has a data property that we can use to send additional values. I originally thought the solution might be to pass through props or something like that but the beauty of value is that it forces us to ensure that the solution we use can fit into value which is Immutable which means that Slate continues to stay functional as much as possible.

So in our case of editing mode, when somebody enables editing mode, we set value by doing something like:

const newValue = value.setIn(['data', 'isEditing'], true)

Now, because value would be passed around through the nodes, we can use the plugins shouldNodeComponentUpdate to force re-render;

function RerenderOnIsEditing() {
  return {
    shouldNodeComponentUpdate(props, nextProps) {
      if (props.value.isEditing !== nextProps.value.isEditing) return true
    }
  }
}

In order to get readOnly to work in the same manner, we can take one of two approaches:

  1. We could build a compatibility layer where if props.readOnly differed from value.data.readOnly then we immediately call the onChange with value.data.readOnly=true to fix that.

  2. This might be better for the future, is we can have the outer component do this where basically instead of passing in a props.readOnly we have them set value.data.readOnly. The reason why the latter might be preferable is because it gets users into the habit of storing all editor state in the value. This makes it obvious that when they want to add, for example, isEditing to the state, it should go in the same place that readOnly already exists. The discoverability would be better at the cost of a bit of ease of use.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:1
  • Comments:13 (5 by maintainers)

github_iconTop GitHub Comments

9reactions
trompxcommented, May 5, 2018

Hey @thesunny,

Any chance you can share how you did it?

In my renderNode function, I render some nodes depending on the previous and next block type. So when changing a node type, the previous and next one should be re rendered.

Despite the awesome documentation, I was not sure how renderNode was called. If I am right, the nodes rendered are the node focused AND the node who lost the focus. Maybe adding that info to the doc could be helpful.

6reactions
thesunnycommented, Feb 15, 2019

Here’s my original code for doing a force refresh but I have a newer version posted below but which I haven’t posted (just wrote right now):

export default function ForceRefreshPlugin() {
  let forceRefresh = false
  return {
    // This method called directly onto the Object.
    // 
    // const forceRefreshPlugin = ForceRefreshPlugin()
    // plugins = [..., forceRefreshPlugin]
    // forceRefreshPlugin.refresh()
    refresh() {
      forceRefresh = true     
    },
    // Cleared after the editor renders once
    componentDidUpdate() {
      forceRefresh = false
    },
    // This code always returns true (forcing the refresh) until the
    // entire Editor is redrawn at which point `componentDidUpdate` gets
    // called and then this returns null which reverts to normal refresh
    // rules.
    shouldNodeComponentUpdate(props, nextProps) {
      return forceRefresh ? true : null
    },
  }
}

The following should work though and uses a command instead.

export default function ForceRefreshPlugin() {
  let forceRefresh = false
  return {
    // Cleared after the editor renders once
    componentDidUpdate() {
      forceRefresh = false
    },
    // This code always returns true (forcing the refresh) until the
    // entire Editor is redrawn at which point `componentDidUpdate` gets
    // called and then this returns null which reverts to normal refresh
    // rules.
    shouldNodeComponentUpdate(props, nextProps) {
      return forceRefresh ? true : null
    },
    commands: {
      refresh() {
        forceRefresh = true
      }
    }
  }
}

You should be able to refresh then using this code:

editor.refresh()
Read more comments on GitHub >

github_iconTop Results From Across the Web

How and when to force a React component to re-render
Forcing an update on a React class component​​ In any user or system event, you can call the method this. forceUpdate() , which...
Read more >
A (Mostly) Complete Guide to React Rendering Behavior
During the rendering process, React will start at the root of the component tree and loop downwards to find all components that have...
Read more >
What is correct way to re-render one component from another ...
When I change select (and call this function) I re-render graph-component by changing it key, and it works just fine. What is better...
Read more >
What is Render in React and How Do You Force it? - Telerik
What exactly is Render in React, how can we force a class or functional component to re-render, and can it be done without...
Read more >
How to force a React component to re-render - Educative.io
React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in...
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