React中的函数绑定后缺少状态值

时间:2017-06-01 12:43:53

标签: javascript reactjs

我是React的新手,现在有些麻烦。
我有一个组件,它捕获一些对象作为道具,几个函数在几秒钟内改变状态一次:



StageWebView

export default class Header extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      variants:   props.variants,
      background: props.variants[0].background
    }
  }
  setTimer () {
    const { variants } = this.state
    clearTimeout(this.timeout)
    this.timeout = setTimeout(this.updateBackground.bind(this), 1000)
  }
  updateBackground () {
    console.log(`Keys ${this.state.variants}`);
    const { variants }    = this.state
    const { background }  = variants[parseInt(Math.random() * 5)]
    setState({
      background: background
    }, this.setTimer)
  }
  componentDidMount() {
    this.setTimer()
  }
  render() {
    const { background } = this.state
    return (
            <div className="header-image"> <img src={ background } /> </div>
      )
  }
}
&#13;
&#13;
&#13;

我的问题是:在

之后
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

调用,updateBackground丢失所有状态值,例如

this.updateBackground.bind(this)

已定义,但不再包含对象,例如

this.state.variants

请向我解释我做错了什么:)

3 个答案:

答案 0 :(得分:1)

我在这里猜一点。道具中的变体最初可能是空的。如果道具将要更改,请在componentWillReceiveProps中设置状态

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

另一个选择是汤姆戴维斯建议的。直接使用道具。

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

答案 1 :(得分:0)

问题在于这行代码

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

当你调用setTimeout时,绑定它的那一刻,你就失去了课堂的范围。试试这个

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

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

答案 2 :(得分:0)

您可以进行一些更改,以提高组件的可读性和可维护性。我假设它应该每1000ms更新一次,因此交换使用setInterval代替以避免重置计时器 - 因为更新图像不是一个长时间运行的操作。

此外,我已添加处理组件卸载时停止间隔/计时器继续尝试运行并对不再存在的组件进行操作。

<强>组件

export default class Header extends React.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 <img className="header" src={this.state.currentBackground} />;
    }
}

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

被称为......

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