Promo Icon

⚡️ Limited Black Friday Deal

Get 50% off on the React Three Fiber Ultimate Course with the promo code ULTIMATE50

Buy Now

$85.00 $42.50

Loading Screen

Starter pack

In 3D experiences, it is common to have complex models and large textures. This can lead to long loading times. To avoid having a blank screen and bad first impressions, we can add a loading screen.

I personally think that when possible, a loading screen should be avoided (Unless it's a design choice). Optimizing models and textures should be considered first.

But sometimes you have no choice, and even optimized models can stay large or you have many of them. In this case, a loading screen can be a good solution.

Suspense

Suspense is a React wrapper component that allows you to render a fallback component while waiting for data to load.

That data in traditional apps refers usually to data fetching or code splitting. But in React Three Fiber, we can use it to wait for models and textures to load.

useLoader hook uses promises to load models and textures. So we can use Suspense to wait for them to resolve.

In the starter pack I have added 4 models in public/models/ of +3MB each. (Which is a lot for a web app as they all contains the same animations and could/should be optimized) That will allow us to see how Suspense works.

When I reload, we have a long blank screen before the models are loaded. This is not a good user experience, users could think that the app is broken and leave.

I you are working locally or have the models cached in your browser, you might not see the blank screen.

To force reloading the resources, you can disable the cache in the Network tab of your browser dev tools.

You can also slow down the network with the Throttling option.

Disable cache and Throttle network

Now we all should see the blank screen, let's add a Suspense component with a fallback prop:

import { Canvas } from "@react-three/fiber";
import { Experience } from "./components/Experience";
import { Suspense } from "react";

const CubeLoader = () => {
  return (
    <mesh>
      <boxGeometry />
      <meshNormalMaterial />
    </mesh>
  );
};

function App() {
  return (
    <>
      <Canvas camera={{ position: [-4, 4, 12], fov: 30 }}>
        <Suspense fallback={<CubeLoader />}>
          <group position-y={-1}>
            <Experience />
          </group>
        </Suspense>
      </Canvas>
    </>
  );
}

export default App;

Our fallback component is a simple cube, it is not the best looking loading screen, but it is enough to understand how Suspense works.

When we reload, we can see that the cube is displayed while the models are loading. When they are loaded, the cube is replaced by the Experience component.

Preload

A common issue you can face is that your resources are not required immediately. For example, you can have a model that is loaded only when the user clicks on a button. So it won't be taken into account by Suspense.

That can lead the fallback component to be displayed again when the resource is required. To avoid that, we can use the preload function from the different Drei loaders.

End of lesson preview

To get access to the entire lesson, you need to purchase the course.