1

I have a problem that I can not resolve in react : I want to change a background image each all 3 seconds. The code work to do this but it involves just one problem : when I update the "teaserAnimCount" state, I can see in my console that this value increase exponentially. I don't know why, with time, it's a problem because the web brother crash.

In the begining, the value of "console.log("this.state.teaserAnimCount") is 1 (it good), then 3, then 7, then 15,... If your are any idea why ?

This is in the renderTeaserBackground arrow function.

My code :

import React, { Component } from 'react';
import teaserImg1 from '../img/teaser-img-1.png';
import teaserImg2 from '../img/teaser-img-2.png';
import teaserImg3 from '../img/teaser-img-3.png';
import teaserImg4 from '../img/teaser-img-4.png'; 
import ProjetTitle from './ProjetTitle';
import { HashLink as Link } from 'react-router-hash-link';
import { TweenMax, Linear } from 'gsap';
import '../plugins/DrawSVGPlugin';

const teaserBgImg = [teaserImg1, teaserImg2, teaserImg3, teaserImg4];

class Teaser extends Component {

  constructor(props) {
    super(props);
    this.state = {
      teaserAnimDuration: 3,
      teaserBg: teaserBgImg,
      teaserAnimCount: 0,
      teaserBgLength: teaserBgImg.length,
      teaserBackground: ''
    }
  }

  componentDidMount() {
    TweenMax.from(
      this.refs.circle,
      this.state.teaserAnimDuration,
      {
        drawSVG: "0%",
        ease: Linear.easeNone,
        repeat: -1
      }
    )
  }

  renderTeaserBackground = () => {
    setTimeout(function() {
      let teaserBackground = this.state.teaserBg[this.state.teaserAnimCount];
      this.setState({teaserAnimCount: this.state.teaserAnimCount + 1});
      this.setState({teaserBackground});
      console.log(this.state.teaserAnimCount);
    }.bind(this), this.state.teaserAnimDuration * 1000);
    return this.state.teaserBackground;
  }

  render() {
    this.renderTeaserBackground();
    let backgroundImg = {
        backgroundImage: 'url(' + this.state.teaserBackground + ')'
    }
    return (
      <Link to="/Content" className="teaser" style={backgroundImg}>
        <svg className="svg-teaser" xmlns="http://www.w3.org/2000/svg">
          <circle ref="circle" cx="50%" cy="50%" r="50%" fill="none"/>
        </svg>
        <div className="teaser-text-container flex">

        </div>
        <ProjetTitle className="teaser-info-teaser"/>
      </Link>
    );
  }
}

export default Teaser;

Thank you for your help.

3 Answers 3

3

It looks like it is calling this.renderTeaserBackground() from render, this function updates the state, and calls the render that calls the state update etc. It crashes because of maximum call stack excedded.

I would try to move the this.renderTeaserBackground(); call to componentWillMount() and just use the state variable inside the render function.

Sign up to request clarification or add additional context in comments.

1 Comment

Change setTimeout to setInterval if you want this to be called multiple times. Be careful though, you'd have to clear the timeout/interval on component unmount.
0

Couple things.

  1. as already mentioned, don't call this.setState in render (calling another function which calls it counts). If you want something to be run just before render, use componentWillMount. If you want something to run just after render, use componentDidMount. The docs suggest using componentDidMount for operations that change state (although I don't think it's a hard rule).
  2. when you're changing state to something that depends on the previous value, it's a good idea to use the callback form of this.setState. The argument is a callback which gives you the current state.
  3. when working with timeouts, make sure you're only creating another timeout as part of the previous timeout. This will prevent multiple timeouts from being "active" simultaneously.
  4. keep a reference to your timeout and, when the component unmounts, clear it.

Here's a working example that covers most of my points: https://jsfiddle.net/69z2wepo/130855/

Comments

0

When the component first load it calls render function which calls renderTeaserBackground function.

renderTeaserBackground function modify the component's state which force the component to re-render again,it executes render and executes renderTeaserBackground function again. and so on ...

move this.renderTeaserBackground from render function to componentDidMount life cycle hook.

Add another call to renderTeaserBackground in setTimeout callback function or use setInterval.

remove this line return this.state.teaserBackground;. it's useless.

4 Comments

Let me know what you get as error when you move this.renderTeaserBackground to componentDidMount
The renderTeaserBackground function it's called just once.
Apparently the error is Hum, it no work again :/ see @Lukasz answer
Saying that does not help anyone help you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.