我自己在下面回答,但是可能会提供一个更“优雅的思考”的更优雅的解决方案..
我正在从CodyHouse创建这个'动画标题'jQuery小部件的React版本:http://codyhouse.co/demo/animated-headlines/index.html(点击'Type')
到目前为止,这么好。我已经让组件工作,以便状态更改正好管理className分配,标题(我的代码中的“短语”)一次动画一个字母,并按顺序循环每个短语,然后重置。
但是,我想要做的是在推进字母时有300ms的定时器间隔,并且当有一个新的短语时暂停2000ms。
目前,尽管我试图在循环新短语时设置更长的animationDelay状态(参见下面代码中的[0a]),但componentDidMount()中的计时器间隔永远不会改变。为什么是这样?如何让componentDidMount()使用当前更改的state.animationDelay?
注意:您可以忽略下面的大部分代码。只有注释行和componentDidMount()才有问题。为了完整,我正在粘贴其余部分。
var React = require('react'),
ClassNames = require('classnames');
var AnimatedPhrases = React.createClass({
getInitialProps: function () {
return {
animateType: 'type'
}
},
getInitialState: function () {
return {
animationDelay:300,
visible: 0,
currentLetter: 0,
currentPhrase: 0,
phraseCount: this.props.phrases.length
}
},
componentDidMount: function(){
this.timer = setInterval(this.tick, this.state.animationDelay);
},
componentWillUnmount: function(){
clearInterval(this.timer);
},
isLastLetter: function () {
var phrases = this.props.phrases;
var currentPhraseLength = phrases[this.state.currentPhrase].name.length;
return (this.state.currentLetter === currentPhraseLength-1);
},
isLastPhrase: function () {
var phrases = this.props.phrases;
var currentPhraseLength = phrases[this.state.currentPhrase].name.length;
return (this.state.currentPhrase === this.state.phraseCount-1
&& this.state.currentLetter === currentPhraseLength-1);
},
tick: function(){
var phrases = this.props.phrases;
var currentPhraseLength = phrases[this.state.currentPhrase].name.length;
// if we are on the last letter of the current phrase, we need
// to increment the current phrase at the next pass [0] and
// pause for longer [0a]
// unless it's the last phrase
// in which case we reset the current phrase and letter. [1]
// If we are in the middle of a word, continue to increment
// only the current letter [2]
if (this.isLastPhrase()) {
this.setState({
currentPhrase: 0, // [1]
currentLetter: 0, // [1]
});
}
if (this.isLastLetter()) {
this.setState({
currentLetter: 0, // [0]
currentPhrase: this.state.currentPhrase+1, // [0]
animationDelay: 2000 // [0a]
});
} else {
this.setState({
currentLetter: this.state.currentLetter+1 // [2]
});
}
},
buildPhrase: function (phrase, index) {
var isVisible = this.state.currentPhrase == index ? true : false;
var classes = ClassNames({
'is-visible': isVisible,
'is-hidden': !isVisible
});
var text = '';
if ( phrase.hasOwnProperty('name') ) {
text = phrase.name;
if (isVisible) {
// cycle through letters and create an <i> per letter
// with class depending on matching the current letter
var splitPhrase = this.singleLetters(text);
if (phrase.hasOwnProperty('url') && phrase.hasOwnProperty('id')) {
return <a className={ classes } key={index} href={phrase.url}>{ splitPhrase }</a>
} else {
return <b className={ classes } key={index}>{ splitPhrase }</b>
}
}
}
},
singleLetters: function (phrase, isVisible) {
var currentLetter = this.state.currentLetter;
var letters = phrase.split("");
var letterCount = phrase.length;
var newLetters = letters.map(function (letter, index) {
return <i className={ currentLetter >= index ? 'in' : 'out' } key={index}>{letter}</i>
});
return newLetters;
},
render: function() {
var buildPhrase = this.buildPhrase;
phrases = this.props.phrases.map(function (phrase, index) {
return buildPhrase(phrase, index);
});
var classes = ClassNames('animated-phrase', this.props.animateType);
return (
<h1 className="animated-phrase letters type">
<span>{this.props.headline}</span>
<span className="word-wrapper waiting">
{ phrases }
</span>
</h1>
)
}
});
module.exports = AnimatedPhrases;
答案 0 :(得分:1)
好的,所以最后,实际上这只是我在tick()中设置状态后清除定时器的情况,如此。如果有人知道更优雅的解决方案(最有可能!),请发帖:)
tick: function(){
var phrases = this.props.phrases;
var currentPhraseLength = phrases[this.state.currentPhrase].name.length;
// if we are on the last letter of the current phrase, we need
// to increment the current phrase at the next pass [0]
// unless it's the last phrase
// in which case we reset the current phrase and letter [1]
// if we are in the middle of a word, continue to increment
// only the current letter [2]
if (this.isLastPhrase()) {
this.setState({
currentPhrase: 0, // [1]
currentLetter: 0, // [1]
});
}
if (this.isLastLetter()) {
this.setState({
currentLetter: 0, // [0]
currentPhrase: this.state.currentPhrase+1, // [0]
animationDelay: 2000
});
// this fixes it!
clearInterval(this.timer);
this.componentDidMount();
} else {
this.setState({
currentLetter: this.state.currentLetter+1, // [2],
animationDelay: 300
});
clearInterval(this.timer);
this.componentDidMount();
}
},