我是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;
我的问题是:在
之后<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
请向我解释我做错了什么:)
答案 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' }]} />