2016-11-05 18 views
1

我的目標是創建一個保存指示器,用於在剛剛保存數據時閃爍保存圖標(不保存,而保存),作爲向用戶表明其編輯成功的指示。反應似乎更適合對狀態比一次性「的行動,」但是這是我能夠拿出最好的:在React中實現瞬時指示器

import React, { PureComponent, PropTypes } from 'react'; 
import Radium from 'radium'; 
import moment from 'moment'; 
import { ContentSave as SaveIcon } from 'material-ui/svg-icons'; 

class SaveIndicator extends PureComponent { 
    getStyles =() => { 
    if (!this.props.saving) return { opacity: 0 }; 

    return { 
     animation: 'x 700ms ease 0s 3 normal forwards', 
     animationName: saveAnimation, 
    }; 
    }; 

    render() { 
    return <div style={styles.root}> 
     <div style={{ display: 'flex' }}> 
     <div style={{ marginRight: 16 }}> 
      Last saved {moment(this.props.lastSaved).fromNow()} 
     </div> 
     <div 
      style={this.getStyles()} 
      onAnimationEnd={() => this.props.onIndicationComplete()} 
     > 
      <SaveIcon color="#666" /> 
     </div> 
     </div> 
    </div> 
    } 
} 

const saveAnimation = Radium.keyframes({ 
    '0%': { opacity: 0 }, 
    '50%': { opacity: 1 }, 
    '100%': { opacity: 0 }, 
}); 

const styles = { 
    root: { 
    display: 'inline-block', 
    }, 
}; 

SaveIndicator.defaultProps = { 
    saving: false, 
}; 

SaveIndicator.propTypes = { 
    lastSaved: PropTypes.object.isRequired, 
    onIndicationComplete: PropTypes.func, 
    saving: PropTypes.bool, 
}; 

export default Radium(SaveIndicator) 

它的工作原理,但有什麼辦法,我可以簡化這一點,並使其更短?

+0

聽起來很棒,也許值得做一個組件,如果還不存在的話。把它稱爲'react-temporary' :) – ZekeDroid

回答

0

這個怎麼樣。我後面有一個組件需要類似於您所描述的內容。我會粘貼它,因爲它完全可以工作,但策略是這樣的:通過一段時間開始動畫。這個道具會觸發一個函數來開始動畫,從而抓住那段時間和「now」之間的差異。它迭代地設置狀態以縮小初始時間和現在之間的差距,直到它超過傳入的持續時間prop。

class SaveIndicator extends Component { 
    static propTypes = { 
     children: Types.element, 
     // time in milliseconds when the save is started; can change 
     indicationStartTime: Types.number.isRequired, 
     // time in milliseconds that the animation will take to fade 
     duration: Types.number, 
     // time in milliseconds to wait between renderings 
     frameRate: Types.number, 
    }; 

    static defaultProps = { 
     duration: 7000, 
     frameRate: 100, 
    } 

    constructor(props) { 
     super(props); 
     this.state = { opacity: 0 }; 
    } 

    componentDidMount() { 
     this.startAnimation(); 
    } 

    componentWillReceiveProps({ indicationStartTime }) { 
     if (indicationStartTime !== this.props.indicationStartTime) { 
      this.startAnimation(); 
     } 
    } 

    startAnimation() { 
     const { indicationStartTime, duration, frameRate } = this.props; 
     const now = new Date().getTime(); 
     const newOpacity = 1 - ((now - indicationStartTime)/duration); 

     if (now - indicationStartTime < duration) { 
      this.setState({ opacity: newOpacity },() => 
       setTimeout(::this.startAnimation, frameRate) 
      ); 
     } else { 
      this.setState({ opacity: 0 }); 
     } 
    } 

    render() { 
     const { children } = this.props; 
     const { opacity } = this.state; 
     const style = { opacity }; 

     return <div style={style}>{children}</div>; 
    } 
} 
+0

上面的小缺陷:你需要將新的道具傳入startAnimation,否則在獲取新的道具之前就會觸發(使用之前的道具值)。這意味着如果在持續時間內兩次觸發事件,您只會看到動畫。 反應文檔片段:_「componentWillReceiveProps()在裝載組件接收新道具之前被調用。」_ –

+0

它在'componentWillMount'期間觸發,所以我認爲它應該是好的 – ZekeDroid

相關問題