Cannot update a component while rendering a different component - Environment / React- Three-Fiber - reactjs

My App.jsx
import "./App.css";
import { Canvas } from "#react-three/fiber";
import React, { Suspense } from "react";
import { Html, useProgress } from "#react-three/drei";
const Scene = React.lazy(() => import('./components/Scene.jsx'));
function Loader() {
const { progress } = useProgress();
return <Html center>{progress} % loaded</Html>
}
function App() {
return (
<div id="canvas">
<Canvas>
<Suspense fallback={<Loader />}>
<Scene />
</Suspense>
</Canvas>
</div>
);
}
export default App;
My Scene.jsx
function Scene() {
<>
<ambientLight intensity={0.2} />
<directionalLight />
<GizmoHelper
alignment="bottom-right"
margin={[80, 80]}
>
<GizmoViewport
axisColors={["red", "green", "blue"]}
labelColor="black"
/>
</GizmoHelper>
<Text
position={[-3, 0, 0]}
anchorX="center"
anchorY="middle"
fontSize="1.5"
outLineBlur="5"
outlineColor="red"
curveRadius="2.9"
font="db.onlinewebfonts.com/t/02654c5f87934978cd2129477ad40869.ttf">
Hello world
<meshStandardMaterial
color="#ec2d2d"
opacity="1"
roughness="0"
metalness="0.3"
normalMap={normalMap}
/>
</Text>
<OrbitControls />
<Environment preset="city" background="true" />
</>
);
}
My problem:
Every time I start the app the environment doesn't load and I get the following error:
Warning: Cannot update a component (`Loader`) while rendering a different component (`Environment`)
If I change the preset while the live server is running the environment updates and shows instantly.
I have already tried to write a function and render the environment only when the window is loaded but I still got the same error.
I have read somewhere I could use a setTimeout but not sure whether this the right approach.
If anyone could point me in the right direction.
Update:
I did not include the fact that I was using the GizmoHelper component.
Removing the GizmoHelper from the scene solved the problem.
I have added the GizmoHelper in above code in case someone else has the same problem.
Further Update:
I noticed the error is still logged in the console but now it does not affect the initial rendering of the environment anymore.
Might still cause an issue further down the road though.

Related

OBJ Model not loading in react three fiber

I'm trying to add an OBJ Model (armchair.obj) but it's not being loaded. I'm using React three fiber library.
Here's my codesandbox: CodeSandbox
There's no problem with the model because I tried to load it using some other website and it is being loaded.
Anyway, I tried uploading another model (spongebob.obj) but it's not being really visible
However, in the other website, it's visible:
So, here's my codesandbox link
But, if you prefer the code here:
My App.js component:
import React, { Suspense } from "react";
import { Canvas } from "#react-three/fiber";
import { OrbitControls } from "#react-three/drei";
import LoadModel from "./components/LoadModel";
import Loader from "./components/Loader";
const App = () => {
return (
<main className="main-area">
<div id="canvas-container">
<Canvas pixelratio={[1, 2]} camera={{ position: [15, 15, 15], fov: 50, scale: [2,2,2] }}>
<ambientLight intensity={1} />
<Suspense fallback={<Loader />}>
<LoadModel url="./spongebob.obj" />
</Suspense>
<OrbitControls />
</Canvas>
</div>
</main>
);
};
export default App;
My LoadModel.js component:
import React, { useMemo, useState } from "react";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
const LoadModel = ({ url }) => {
const [obj, set] = useState();
// useMemo(() => new OBJLoader().load(url, set), [url])
useMemo(() => new OBJLoader().load(url, set), [url]);
//useMemo(() => new GLTFLoader().load(url, set), [url])
return obj ? <primitive object={obj} dispose={null} /> : null;
};
export default LoadModel;
You can improve the rendering of the SpongeBob model by adding a directional light to your scene. A single ambient light is not sufficient for proper illumination. Try adding the following line to your codesandbox:
<directionalLight />
The chair model has unfortunately some design issues. It has an extreme scale and is highly translated. I suggest you scale the model down and then center it after the loading process. However, it would be better to fix the model in a DCC tool like Blender and model the chair according to real world units.

Implementation of react-intersection-observer module not working on multiple components

I am struggling with the implementation of the "react-intersection-observer" and i can't for the life of me find a solution.
Details:
I have a simple presentation site which i wanna do with React so i can also learn. Right now the website has only the homepage and the homepage has so far these sections: header, about, portfolio and contact form.
What i wanna do is to simply add a class on each section (about, portfolio and contact form) once the section is in viewport. The kind of stuff that with jquery would be over in 2 minutes.
I have installed "react-intersection-observer" and so far the code in my homepage.component.jsx looks like this:
import React from 'react';
import Header from "../../components/header/header.component";
import About from "../../components/about/about.component";
import PortfolioList from "../../components/portfolio-list/portfolio-list.component";
import ContactForm from "../../components/contact-form/contact-form.component";
import { useInView } from 'react-intersection-observer';
const HomePage = () => {
const { ref, inView, entry } = useInView({
/* Optional options */
triggerOnce: true,
threshold: 1,
onChange: (inView, entry) => {
console.log("salam");
console.log(inView);
console.log(entry);
if (inView) {
entry.target.classList.add("in-view");
}
}
});
return (
<div>
<Header/>
<main className="main">
<About />
<PortfolioList />
<ContactForm />
</main>
</div>
);
};
export default HomePage;
When i have added ref={ref} on each component like this:
<About ref={ref} />
<PortfolioList ref={ref} />
<ContactForm ref={ref} />
i have received an error: Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
The thing is that i don't want to add the useInView module in each of the 3 jsx components because it seems bad practice to have repeat code.
Passing ref as props is bad practice.
Use React.forwardRef instead:
https://beta.reactjs.org/apis/react/forwardRef
Check this example:
https://beta.reactjs.org/apis/react/forwardRef#forwarding-a-ref-through-multiple-components

Rendering glb file in React using npx gltfjsx model.glb command

I am trying to add animation to my React project. Animation is taken from mixamo.com and then exported to a glb file using blender. I saved the glb file in my public folder. Next, I used:
npx gltfjsx model.glb
but I receive the following error:
ERROR Objects are not valid as a React child (found: Error: Invalid hook call. Hooks can only be called inside of the body of a
function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.). If you meant to render a
collection of children, use an array instead.
- 1. You might have mismatching versions of React and the renderer (such as React DOM)
- 2. You might be breaking the Rules of Hooks
- 3. You might have more than one copy of React in the same app
- See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.). If you meant to render a
collection of children, use an array instead.
- throwOnInvalidObjectType (node_modules/ink/node_modules/react-reconciler/cjs/react-reconciler.development.js:4612:15)
- createChild (node_modules/ink/node_modules/react-reconciler/cjs/react-reconciler.development.js:4850:7)
- reconcileChildrenArray (node_modules/ink/node_modules/react-reconciler/cjs/react-reconciler.development.js:5100:25)
- reconcileChildFibers (node_modules/ink/node_modules/react-reconciler/cjs/react-reconciler.development.js:5506:14)
- reconcileChildren (node_modules/ink/node_modules/react-reconciler/cjs/react-reconciler.development.js:8417:28)
- updateHostComponent (node_modules/ink/node_modules/react-reconciler/cjs/react-reconciler.development.js:9059:3)
- beginWork (node_modules/ink/node_modules/react-reconciler/cjs/react-reconciler.development.js:10507:14)
- Object.invokeGuardedCallbackProd (node_modules/ink/node_modules/react-reconciler/cjs/react-reconciler.development.js:12101:10)
- invokeGuardedCallback (node_modules/ink/node_modules/react-reconciler/cjs/react-reconciler.development.js:12292:31)
- beginWork$1 (node_modules/ink/node_modules/react-reconciler/cjs/react-reconciler.development.js:16531:7)
If I try to manually add the Model.js file using:
import React, { useRef, useEffect } from 'react';
import { useGLTF, useAnimations } from '#react-three/drei';
export default function Model({ ...props }) {
const group = useRef();
const { nodes, materials, animations } = useGLTF('/model.glb');
const { actions } = useAnimations(animations, group);
// 'Armature|mixamo.com|Layer0' is the name of the animation we need to run.
// console.log(actions);
useEffect(() => {
actions['Armature|mixamo.com|Layer0'].play();
});
return (
<group ref={group} {...props} dispose={null}>
<primitive object={nodes.Hips} />
<skinnedMesh
geometry={nodes.Wolf3D_Body.geometry}
material={materials.Wolf3D_Body}
skeleton={nodes.Wolf3D_Body.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Glasses.geometry}
material={materials.Wolf3D_Glasses}
skeleton={nodes.Wolf3D_Glasses.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Hair.geometry}
material={materials.Wolf3D_Hair}
skeleton={nodes.Wolf3D_Hair.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Bottom.geometry}
material={materials.Wolf3D_Outfit_Bottom}
skeleton={nodes.Wolf3D_Outfit_Bottom.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Footwear.geometry}
material={materials.Wolf3D_Outfit_Footwear}
skeleton={nodes.Wolf3D_Outfit_Footwear.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Top.geometry}
material={materials.Wolf3D_Outfit_Top}
skeleton={nodes.Wolf3D_Outfit_Top.skeleton}
/>
<skinnedMesh
name="EyeLeft"
geometry={nodes.EyeLeft.geometry}
material={nodes.EyeLeft.material}
skeleton={nodes.EyeLeft.skeleton}
morphTargetDictionary={nodes.EyeLeft.morphTargetDictionary}
morphTargetInfluences={nodes.EyeLeft.morphTargetInfluences}
/>
<skinnedMesh
name="EyeRight"
geometry={nodes.EyeRight.geometry}
material={nodes.EyeRight.material}
skeleton={nodes.EyeRight.skeleton}
morphTargetDictionary={nodes.EyeRight.morphTargetDictionary}
morphTargetInfluences={nodes.EyeRight.morphTargetInfluences}
/>
<skinnedMesh
name="Wolf3D_Head"
geometry={nodes.Wolf3D_Head.geometry}
material={materials.Wolf3D_Skin}
skeleton={nodes.Wolf3D_Head.skeleton}
morphTargetDictionary={nodes.Wolf3D_Head.morphTargetDictionary}
morphTargetInfluences={nodes.Wolf3D_Head.morphTargetInfluences}
/>
<skinnedMesh
name="Wolf3D_Teeth"
geometry={nodes.Wolf3D_Teeth.geometry}
material={materials.Wolf3D_Teeth}
skeleton={nodes.Wolf3D_Teeth.skeleton}
morphTargetDictionary={nodes.Wolf3D_Teeth.morphTargetDictionary}
morphTargetInfluences={nodes.Wolf3D_Teeth.morphTargetInfluences}
/>
</group>
);
}
useGLTF.preload('/model.glb');
in console, the object is showing empty and the app is not working (an empty page shows up with just the background color) while the following error is received in the console:
Error message showing browser console
Avatar.jsx where I want to render the Model.js
import React, { Suspense } from "react";
import { Canvas } from "#react-three/fiber";
import { OrbitControls } from "#react-three/drei";
import Model from "./Model";
function Avatar() {
return (
<Canvas camera={{ position: [2, 0, 12.25], fov: 15 }}>
<ambientLight intensity={1.25} />
<ambientLight intensity={0.1} />
<directionalLight intensity={0.4} />
<Suspense fallback={null} r3f>
<Model />
</Suspense>
<OrbitControls />
</Canvas>
);
}
Any help or suggestions are welcome. (Before adding animation I was able to add the 3D image in my project, the app was working fine.)

Control model size using react-three-fiber

I'm new to react-three-fiber, so I really think my problem is easy but I almost give up on it 😅.
the problem :
I have a 3D model it renders ok but it’s away too big
I have to zoom out to 25% just to see almost half the model (see the picture)
what I wanted:
the model to be way smaller so I can put it as a small background for my website.
Here’s the full model
I want to put the model.js but it’s too many lines 😅, there’s nothing special really I use the gltfjsx command line to transfer my .gltf file to .js file and I didn’t do any changes to it.
and here's my app.js
import React, { Suspense } from "react";
import { Canvas } from "#react-three/fiber";
import { OrbitControls } from "#react-three/drei";
import './App.css';
import Model from './components/Bedroom';
function App() {
return (
<Canvas>
<OrbitControls />
<ambientLight intensity={0.6} />
<directionalLight intensity={0.5} />
<Suspense fallback={null}>
<Model/>
</Suspense>
</Canvas>
);
}
export default App;
use Stage from 'three/drei' to stage your model it will fix this issue,
example:
<Canvas>
<Stage preset="rembrandt" intensity={1} environment="city">
<Model/>
...
<Stage/>
<Canvas/>
Or:
control your zoom inside camera of canvas like this
<Canvas camera={{ fov: 35, zoom: 1.3, near: 1, far: 1000 }}>
...
<Canvas/>
Myabe you are just trying to scale your model, in that case you just need to add scale={[sclaefactorx,scalefactory,sclaefactorz]} on your model like so :
import { Canvas } from "#react-three/fiber";
import { OrbitControls } from "#react-three/drei";
import './App.css';
import Model from './components/Bedroom';
function App() {
return (
<Canvas>
<OrbitControls />
<ambientLight intensity={0.6} />
<directionalLight intensity={0.5} />
<Suspense fallback={null}>
<Model scale={[0.1,0.1,0.1]}/>
</Suspense>
</Canvas>
);
}
export default App;
Since in the model file created from gltfjsx there should be a {...props} on the created group the scale will be applied directly to the mesh group

White screen in expo when another file is being imported to app.js

This is the app.js file, which has no error in it. But when AbcdPage is being imported from AbcdPage.js file the entire simulator & emulator goes entirely white. Nothing is being displayed also terminal in vscode doesn't show any error or warnings.
import React, { Component } from 'react';
import AbcdPage from "./components/AbcdPage"
export default class App extends Component {
render() {
return (
<View>
<AbcdPage />
</View>
);
}
}
Here goes AbcdPage.js file, all imports are done correctly in this AbcdPage.js file.
const Drawer = createDrawerNavigator();
export default function AbcdPage(props) {
return (
<NavigationContainer>
<Drawer.Navigator
drawerPosition="right"
drawerContent={(props) => <DrawerContent {...props} />}
>
<Drawer.Screen name="HomeDrawer" component={Screen1} />
</Drawer.Navigator>
</NavigationContainer>
);
}
Thanks in advance for your help.
Try to add to your View component style flex:1

Resources