How to update a CSS Grid without re-rendering a specific component in ReactJS?

Viewed 313

I'm working on a React website with a video player that should continuously play on all routes. I'm trying to figure out a way to build a specific dynamic layout using CSS Grid that will update itself and the state of all components except the video component.

The main challenge is to make sure that the video component does not re-render in order to avoid any interruption in the playback.

The Homepage (initial) layout is the following:

First Layout

// Code from an online generator
<div class="container">
  <div class="Video"></div>
  <div class="Content"></div>
  <div class="Sidebar"></div>
</div>

.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  gap: 0px 0px;
  grid-auto-flow: row;
  grid-template-areas:
      "Video Video Sidebar"
      "Content Content Sidebar"
      ". . .";
  }

.Video { grid-area: Video; }
.Content { grid-area: Content; }
.Sidebar { grid-area: Sidebar; }

All other routes layout is the following:

enter image description here

// Code from an online generator
<div class="container">
    <div class="Content"></div>
    <div class="Video"></div>
    <div class="Sidebar"></div>
</div>

.container {  display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 1fr 1fr 1fr;
    gap: 0px 0px;
    grid-auto-flow: row;
    grid-template-areas:
        "Content Content Video"
        "Content Content Sidebar"
        ". . .";
}

.Content { grid-area: Content; }
.Video { grid-area: Video; }
.Sidebar { grid-area: Sidebar; }

Is it possible to transition from Layout 1 to Layout 2 using CSS Grid without re-rendering the video component?

1 Answers

I managed to implement it by creating a layout with the video Component 1 outside of the Switch and passing the rest of the components as {children} of the layout.

I created two different grid-area CSS attribute versions for each component, for each layout, and used them to place the components in the grid cells according to the design.

Finally, I used useLocation() to get the current route and conditionally switch between the grid-area classes.

/* CSS */
.parent {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-column-gap: 20px;
  grid-auto-rows: minmax(100px, auto) minmax(max-content, 2fr);
}

.video {
  grid-area: 1 / 1 / 9 / 10;
}

.sidebar {
  grid-area: 1 / 10 / 13 / 13;
}

.content {
  grid-area: 9 / 1 / 13 / 10;
}

.video-alt {
  grid-area: 1 / 10 / 1 / 13;
}

.sidebar-alt {
  grid-area: 2 / 10 / 13 / 13;
}

.content-alt {
  grid-area: 1 / 1 / 13 / 10;
}

// JSX
export const isHome = () => {
    let location = useLocation();
    return location.pathname === "/";
}

<div className="container mx-auto">
    <Header />
    <div className='parent'>
        <Stream />
        {isHome() ? <Chat /> : null}
        <div className={isHome() ? "content" : "content-alt"}  >
            {children}
        </div>
    </div>
    <Footer/>
</div>


// <Stream />
<div className={!isHome() ? "video-alt sticky top-20 z-40" : "video"}>
    <div ref={ref} className="">
        <VideoJS options={videoJsOptions} onReady={handlePlayerReady}/>
   </div>
   <div className="mt-4">{!isHome() ? <Chat /> : null}</div>
</div>
Related