Load Component Only once in React js

Viewed 1102

So I have a React App And it has 2 pages Lets say 1st one is Home and 2nd one is My Portfolio Section And My Portfolio Section has 2 functional components in it

Home.js

import React from 'react'

const Home = () => {
  return (
    <h1>Home Screen</h1>
  )
}

export default Home

Portfolio Section

import React from 'react'
import Projects from '../components/Projects'
import Testimonials from '../components/Testimonials'
const Portfolio = () => {
  return (
    <>
    <h1>Portfolio</h1>
    <Projects/>
    <Testimonials/>
    </>
  )
}

export default Portfolio 

When I visit Home , Portfolio everything loads fine but when I re-visit them again they again reload each and everytime

I don't want the Projects component in the Portfolio Section to load more than once I want it to load only once on the Startup / when launching the site even before visiting the Portfolio section ( that is in background ) as it has large files that will take time to load and stay the same until user refreshes the page voluntarily .

The component has some 3d models in it which uses three.js So it is not a static site It will have its own animation But the entire component loading each time the page visited will take a lot of time

But the Testimonials component will change dynamically

So in 2 of the components I want one to stay the same without reloading And other to change dynamically

How can I make a component load only once Any suggestion would help me I saw UseMemo but I don't know whether that would help me If so can someone explain how to use it in my case

1 Answers

When the relevant component (Projects) is first rendered, create the animation, and cache it in a variable that is external to the component (let animation in the example). Whenever the component is mounted, get the the animation from the external variable, and start it. And when it's unmounted stop the animation.

Note: This would work if you only render a single instance of the component. If you're going to render multiple instances, you'll need to come up with a system to cache an rerender an animation for each instance - probably some kind of a Map with a constant id for each instance.

Example - toggle the pages, and the animation would continue

const { Fragment, useState, useEffect, useRef } = React

let animation

const Projects = () => {
  const container = useRef();
  
  useEffect(() => {    
    if(!animation) {
      animation = createAnimation()
    }
    
    container.current.appendChild(animation.domElement)
    
    animation.start()
    
    return () => animation.stop()
  }, [])

  return (
    <div ref={container} /> 
  )
}

const Home = () => (
  <span>Home Screen</span>
)

const Portfolio = () => (
  <Fragment>
    <span>Portfolio</span>
    <Projects />
  </Fragment>
)

const App = () => {
  const [showPortfolio, setShowPortfolio] = useState(false)

  return (
    <div>
      <button 
        onClick={() => setShowPortfolio(!showPortfolio)}>
        Toggle
      </button>
      
      {showPortfolio ? <Portfolio /> : <Home />}
    </div>
  )
}

ReactDOM.render(
  <App />,
  root
)

function createAnimation() {
  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(20, window.innerWidth / window.innerHeight, 1, 1000);

  const renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth / 2, window.innerHeight / 2);

  const geometry = new THREE.BoxGeometry();
  const material = new THREE.MeshBasicMaterial({
    color: 0x00ff00
  });
  const cube = new THREE.Mesh(geometry, material);
  scene.add(cube);

  camera.position.z = 5;

  let requestId;

  const animate = () => {
    requestId = requestAnimationFrame(animate);

    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;

    renderer.render(scene, camera);
  };

  return {
    start: animate,
    stop: () => cancelAnimationFrame(requestId),
    domElement: renderer.domElement
  }
}
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r126/three.min.js" integrity="sha512-n8IpKWzDnBOcBhRlHirMZOUvEq2bLRMuJGjuVqbzUJwtTsgwOgK5aS0c1JA647XWYfqvXve8k3PtZdzpipFjgg==" crossorigin="anonymous"></script>

<div id="root"></div>

Related