Search the Community
Showing results for tags 'redux'.
-
i am facing a problem where Three.js objects, specifically a sphere with a ShaderMaterial, disappear after certain state changes. The issue seems to occur when the selected state is updated using dispatch(setSelected()). This triggers a React re-render or reconciliation process, which may interfere with the Three.js object's lifecycle, causing the material or mesh to lose its state or become invisible. The object only remains visible if the state is not updated after setting its properties Here is the code for the object : function App() { const selected = useSelector((state) => state.gsap.selected); const dispatch = useDispatch(); function AnimatedSphere() { const sphereRef = useRef(); const material = useRef( new THREE.ShaderMaterial({ vertexShader, fragmentShader, uniforms: { time: { value: 0.0 }, pinkEraser: { value: new THREE.Color(237/255, 163/255, 152/255) }, opacity : {value : 0.0} }, transparent: true, }) ); useFrame(({ clock }) => { material.current.uniforms.time.value = clock.getElapsedTime(); }); useGSAP(() => { console.log(selected) if(selected == "1" || selected == undefined){ gsap.to(material.current.uniforms.opacity, { value: 1, duration: 1, delay: 0.5, onComplete: () => { dispatch(setSelected("2")); } }); } },[]) useGSAP(() => { if(selected === "3") { gsap.set(sphereRef.current.scale, { x: 2.5/3.1, y: 2.5/3.1, z: 2.5/3.1 }); gsap.to(sphereRef.current.scale, { x: 1, y: 1, z: 1, delay: 0.5, duration: 0.8, onComplete: () => { dispatch(setSelected("4")); } }); } }, [selected]); return ( <mesh ref={sphereRef} material={material.current}> <sphereGeometry args={[2.5, 32, 64]} /> </mesh> ); } return ( <Canvas> <ambientLight /> <OrbitControls /> <AnimatedSphere /> </Canvas> ); } export default App; And i have a redux state that basically just has the number which sequence should run
-
Hello, I'm having trouble trying to debug what is going wrong with my animations. I was able to use mock data and get the desired effect of having my animation stagger through my array of card objects. However, once I started using real data my animations will no longer trigger. Now there are a few strange observations I made: 1. My data is making it into the gsap related mapping func (I have a console log that is proving the cards do exist inside the map) 2. The callback at the very end of my animation is still firing and updating state. So, in short, despite it working with mock data when I switched over to 'live-data' it no longer even triggers the animation despite the `console.log` showing that there is indeed data to map over and the fact that the callback at the end of the animation still triggers... Any ideas? Here is the component: import React, { Component } from "react"; import { connect } from "react-redux"; import "./PlayerHand.scss"; import TreasureCard from "../TreasureCard/TreasureCard"; import ActionCard from "../ActionCard/ActionCard"; import Card from "../Card/Card"; import { TimelineMax } from "gsap"; import { gsapCardsCycleIn } from "../../greenSock/animations"; import { mockPlayerData } from "../../mockData"; export class PlayerHand extends Component { constructor(props) { super(props); this.cards = []; this.tl = new TimelineMax({ paused: true }); this.state = { renderHand: false }; } componentDidMount = () => { gsapCardsCycleIn(this.tl, this.cards, this.showUserHand); }; // componentDidUpdate(prevProps, prevState) { // if (prevProps.playerHand !== this.props.playerHand) this.tl.restart(); // } showUserHand = () => { this.setState({ renderHand: true }); }; render() { // this.tl // .kill() // .clear() // .pause(0); return ( <React.Fragment> <section className='hand-animations'> {this.props.playerHand && this.props.playerHand.map((card, i) => { // this console.log is logging the relevant data, but for some reason nothing is animating console.log(card); return ( <div className='animated-card' key={i} ref={div => (this.cards[i] = div)}> <p>{card.name}</p> </div> ); })} </section> <button onClick={() => this.tl.play()}>Start</button> <button onClick={() => this.tl.reverse()}>Reverse</button> <button onClick={() => this.tl.restart()}>Restart</button> <section className='PlayerHand' style={ this.state.renderHand ? { transform: "translateY(50%)" } : { transform: "translateY(100%)" } } > {this.state.renderHand && this.props.playerHand.map(card => { if (card.category[0] === "Money") { return <TreasureCard card={card} key={card.id} />; } if (card.category[0] === "Action") { return <ActionCard card={card} key={card.id} />; } if (card.category[0] === "Victory") { return ( <Card name={card.name} desc={card.desc} category={card.category} image={card.image} cost={card.cost} id={card.id} key={card.id} /> ); } })} </section> </React.Fragment> ); } } export const mapStateToProps = state => ({ playerHand: state.playerHand }); export default connect(mapStateToProps)(PlayerHand); Here is the GSAP animation I built and imported import { Back } from "gsap"; export const gsapCardsCycleIn = (timeline, dataArray, onComplete) => { timeline .to( dataArray, 0.8, { scale: 1.09, opacity: 1, ease: Back.easeInOut.config(10) }, 0.3 ) .staggerTo( dataArray, 0.4, { left: "45vw", bottom: "25vh", scale: 1.4, cycle: { rotation: i => Math.random() * ((i + 3) * 2), ease: i => Back.easeOut.config((i + 1) * 0.5) } }, 1.2 ) .staggerTo( dataArray, 0.5, { left: "45vw", bottom: "5vh", rotation: 0, scale: 1 }, 0.2 ) .to(dataArray, 0.7, { opacity: 0, y: "100vh", ease: Back.easeInOut.config(1.2), delay: 0.4 }) .to(dataArray, 0, { onComplete: onComplete, delay: 1 }); };