Skip to content Skip to sidebar Skip to footer

Missing State Value After Function Binding In React

Im new to React and have some trouble right now. I have component, which catches some object as props and few functions to change state once at few seconds: My problem is: after

Solution 1:

I am guessing a little bit here. The variants in props maybe empty initially. If the props are going to change, set state in componentWillReceiveProps

componentWillReceiveProps(nextProps) {
  if (nextProps.variants !== this.props.variants) {
    this.setState({ variants: nextProps.variants });
  }
}

The other option is what Tom Davies suggested. Use the props directly.

  updateBackground () {
    const { variants }    = this.props
    const { background }  = variants[parseInt(Math.random() * 5)]
    this.setState({
      background
    }, this.setTimer);
  }

Solution 2:

The problem is this line of code

this.timeout = setTimeout(this.updateBackground.bind(this), 1000)

When you call setTimeout, the very moment you bind it, you lost the scope of the class. Try this

constructor(props) {
    super(props)
    this.state = {
      variants:   props.variants,
      background: props.variants[0].background
    }
    this.updateBackground = this.updateBackground.bind(this)
  }

And

this.timeout = setTimeout(() =>this.updateBackground(), 1000)

Solution 3:

You can make quite a few changes to improve the readability and maintainability of your component. I've assumed that it should update every 1000ms and so swapped to use setInterval instead to avoid having to keep resetting the timer - since updating the image is not a long running operation anyway.

Additionally, I've added handling for when the component unmounts to stop the interval/timer from continuing to try and run and act on a component that is no longer there.

Component

exportdefaultclassHeaderextendsReact.Component {

    constructor(props) {
        super(props);

        // We can just use props, don't need to copy variants// into state since it's never changed.this.state = {
            currentBackground: props.variants[0].background,
            intervalId: null
        };

        // I'll bind everything in the constructor, so it's// only done once and removes clutter from methods.this.updateBackground = this.updateBackground.bind(this);
    }

    componentDidMount() {
        // Do everything we need to on startup here, since it's only// setting the update interval, won't break it out into// separate functions.this.setState({
            intervalId: setInterval(() =>this.updateBackground(), 1000)
        });
    }

    componentWillUnmount() {
        // When the component is unmounted, stop the interval.clearInterval(this.state.intervalId);
    }

    updateBackground() {
        // Assuming you wanted a whole number here, in which case// floor() makes more sense than parseInt(). We should use// variants.length rather than assuming there are 5 entries.let index = Math.floor(Math.random() * this.props.variants.length);

        this.setState({
            currentBackground: this.props.variants[index].background
        })
    }

    render() {
        // Somewhat opinionated, but there doesn't seem to be any reason// to wrap this in a <div>. You could then rename this component// and reuse it anywhere you wanted a random image.return<imgclassName="header"src={this.state.currentBackground} />;
    }
}

Header.propTypes = {
    variants: React.PropTypes.array.isRequired
};

Called like...

<Header variants={[{ background: 'abc.png' }, { background: 'def.png' }]} />

Post a Comment for "Missing State Value After Function Binding In React"