React组件之高阶函数替换Mixins注入 · Web前端爱好者
实现功能
基于ES6用React实现一个倒计时组件,格式:6时6分6秒,然后每隔一秒不断倒计时。
回顾Mixins
当然,完全可以直接写在一个React.createClass函数里面,但可复用性不高,所以换做在之前官方推荐的做法就是利用Mixins特性,所谓Mixins我理解就是注入,类似于Java Spring的依赖注入,简单代码如下:
// 定义一个倒计时Mixins var SetIntervalMixin = { componentWillMount: function() { this.intervals = []; }, setInterval: function() { this.intervals.push(setInterval.apply(null, arguments)); }, componentWillUnmount: function() { this.intervals.forEach(clearInterval); } }; // 注入Mixins到组件中 var Timer = React.createClass({ mixins: [SetIntervalMixin], getInitialState: function() { return { timestamp: this.props.timestamp } }, componentDidMount: function() { this.setInterval(this.changeState, 1000); }, changeState: function() { this.setState({ timestamp: this.state.timestamp - 1000 }) }, render: function() { //取得属性值 var timestamp = this.state.timestamp; return <p>{this.renderTime(timestamp)}</p> }, renderTime(timestamp){ // 省略掉时间计算转换 ... return 'XX天XX时XX分XX秒'; } }); //渲染React元素 ReactDOM.render( <Timer timestamp="66666666"/> , document.querySelector("body") ); |
用Mixins的最大好处就是复用,保证组件的最小颗粒化,同时也保证了功能相对单一。
ES6的高阶函数
但是用ES6来写的话,Mixins显得有点无力,没有办法注入,这个时候高阶函数就派上用场了,其实Redux的connect就是利用了这一特性,改写上面的代码如下:
// 注意这里传入一个React组件然后返回一个React组件 var SetIntervalMixin = ComposedComponent => class extends React.Component { constructor(props) { super(props); this.state = { timestamp: this.props.timestamp } } componentDidMount() { this.interval = setInterval(this.changeState.bind(this), 1000); } componentWillUnmount() { clearInterval(this.interval); } changeState() { this.setState({ timestamp: this.state.timestamp - 1000 }); } render() { return <ComposedComponent {...this.props} {...this.state} />; } }; class Timer extends React.Component { constructor(props) { super(props); } render() { // 注意,这里通过props取得属性值 var timestamp = this.props.timestamp; return <p>{this.renderTime(timestamp)}</p> } renderTime(timestamp){ // 省略掉时间计算转换 ... return 'XX天XX时XX分XX秒'; } } export default SetIntervalMixin(Timer); //渲染React元素 ReactDOM.render( <Timer timestamp="66666666"/> , document.querySelector("body") ); |