Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: Prevent remount when parent rerenders

I've got a component, Split, which takes two children. The first child will be displayed on the left hand side of the screen & the second child on the right hand side. If the screen width goes below a certain point then only the right side will be displayed and the left side will be removed from the DOM.

Example children could be a Sidebar component and a Content component. For mobile devices i don't want to display the menu, but have a special mobile menu that i pop up.

My question is: How can i remove the Sidebar component without unmounting & remounting the Content component too?

My Content component fetches data on componentDidMount and i don't want it to refetch or re-mount(thus discarding user input) again.

Basically i have something like this:

<Split>
  <Sidebar/>
  <Content/>
</Split>

And Split's render method looks something like this:

let children;
let firstChild = this.props.children[0];
let lastChild = this.props.children.pop();
if (this.state.responsive === 'singleColumn') {
  children = (
    <div>
      <div style={{display: 'none'}}>{firstChild}</div>
      {lastChild}
    </div>
  );
} else {
  children = (
    <div>
      {firstChild}
      {lastChild}
    </div>
  );
}

return (
  <div>
    {children}
  </div>
);

Even though {lastChild} is always rendered, no matter what, it still gets unmounted and remounted each time split has to re-render!

Even having a render that looks like this:

return (
  <div>
    {this.props.children.pop()}
  </div>
);

causes the last child(which never changes) to be unmounted & remounted before being rendered.

If i instead modify Split and pass the component that will always be in the DOM as an attribute like so:

<Split staticComponent={<Content />}>
  <Sidebar />
</Split>

it works fine. Then why doesn't it work when im just popping the last child like this {this.props.children.pop()} as opposed to this {this.props.staticComponent}

Is there a sane way to solve this?

like image 848
Oscar Linde Avatar asked Mar 23 '16 18:03

Oscar Linde


1 Answers

Finally managed to solve the issue! I re-wrote Split's render to look something like this:

let left;
if (this.state.responsive !== 'singleColumn') {
  left = this.props.children.slice(0, -1);
}

return (
  <div ref="split" className={classes.join(' ')}>
    {left}
    {this.props.children[this.props.children.length-1]}
  </div>
);

This way the last child always gets rendered. Obviously pop() didn't work because then i modified the original array of children which triggered the weird behavior.

like image 90
Oscar Linde Avatar answered Sep 30 '22 02:09

Oscar Linde