How would I delay a slow React child from re-rendering so the parent can repaint the dom immediately?

Viewed 35

Suppose you had a React App component with a child component that was slow to mount (in my case a 3rd party document editor). The App has to re-render whenever the document changes, and the two child components (the header (which simply displays title, id), the document editor (slow to initially render when initializing a document)) should be able to re-render and repaint the dom as soon as they finish updating. However, the document editor, because it is a slow to initialize, prevents the header from repainting until it is complete. Below is an illustration, where the FastChild will not be repainted until the SlowChild returns.

export default function App() {
  const [count, setCount] = useState(0);
  return (
    <div className="App">
      <FastChild count={count} />
      <button onClick={() => setCount(count+1)}>increment</button>
      <SlowChild count={count}/>
    </div>
  );
}

function FastChild({ count }) {
  return (
    <h1>{count}</h1>
  )
}

function SlowChild({ count }) {

  return veryLongList.map(()=> (
    <div>
      {`count ${count}`}
    </div>
  ))
}

Unfortunately, I cannot make changes the document editor (which would be the SlowChild component in this example).

1 Answers

One solution is to keep a copy of the prop in state, and use shouldComponentUpdate to delay the slow component from rendering using setImmediate

class DelayedSlowChild extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      localCount: props.count,
    }
  }

  shouldComponentUpdate = (nextProps, nextState) => {
    if (nextProps.count !== this.props.count) {
      setImmediate(() => this.setState({ localCount: nextProps.count }))
      return false;
    } else if (this.state.localCount !== nextState.localCount) {
      return true;
    }
    return false
  }

  render() {
    veryLongList.map(i => (
        <div>
          {`${i} ${this.props.count}`}
        </div>
    ))
  }
}
Related