1. 程式人生 > 實用技巧 >React倒計時功能實現——解耦通用

React倒計時功能實現——解耦通用

React倒計時功能實現——解耦通用

需求分析

需求

在某個頁面中需要有一個倒計時的功能,倒計時 5 s,5s鍾後跳轉到新的介面

分析

  • 首先是實現倒計時功能
  • 其次是實現在每倒計時 1 s後頁面上要執行 倒計時秒數變化的功能
  • 最後是實現倒計時完成後 跳轉到指定頁面的功能

初版做法

程式碼

let waitTime = 5
class DemoPage extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			time: '',
		};
	}
	componentDidMount = () => {
		this.countDown();
    };
	countDown = () => {
        if (waitTime > 0) {
            waitTime--;
           this.setState({
               time:waitTime
           })
        } else {
            history.push('/Login')
            return;
        }
        setTimeout(() => {
            this.countDown();
        }, 1000);
	}

	render() {
		todoInfo = this.state.time + '秒後跳轉至登入介面';
		return (
			<div>
				todoInfo
			</div>
		);
	}
}
export default DemoPage;

問題分析

時間設定為全域性變數,糟糕的做法,

  • 修改不方便
  • 難於閱讀和理解
  • 全域性變數的值極不安全,可能被任何程式修改

改進版

程式碼

class DemoPage extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			time: '',
		};
	}
	componentDidMount = () => {
		this.countDown(5);//倒計時時間可隨意調整,且可讀性強
    };
	countDown = (waitTime) => {
        if (waitTime > 0) {
            waitTime--;
           this.setState({
               time:waitTime
           })
        } else {
            history.push('/Login')
            return;
        }
        setTimeout(() => {
            this.countDown(waitTime);
        }, 1000);
	}

	render() {
		todoInfo = this.state.time + '秒後跳轉至登入介面';
		return (
			<div>
				todoInfo
			</div>
		);
	}
}
export default DemoPage;

改進後將時間作為引數放到countDown裡面,方便隨意設定倒計時時間

進一步分析問題:

上面的做法,

  • setState的操作只能寫在本元件,與本元件緊耦合在一起,無法實現多元件複用
  • history.push('/Login') 只能用在umi 框架中,與框架緊耦合在一起,無法實現普適應用

進一步改進

針對本問題的需求,可以將業務場景擴大為:

  • 倒計時功能
  • 倒計時過程中 需要做某事 doSomethingDuringCountDown()
  • 倒計時結束後 需要做某事 doSomethingAfterCountDown()

這樣的話,倒計時的功能就可以使用的更加的靈活了。

方案

將函式作為引數傳遞到countDown()方法中

doSomethingDuringCountDown()doSomethingAfterCountDown()作為引數傳遞到countDown方法中,

具體的方法實現,根據自己頁面的需求來實現。

程式碼

//utils.js

export countDown = (waitTime,doSomethingDuringCountDown,doSomethingAfterCountDown){
      if (waitTime > 0) {
        waitTime--;
          if(doSomethingDuringCountDown){
               doSomethingDuringCountDown()
          }    
        } else {
            if(doSomethingAfterCountDown){
                doSomethingAfterCountDown()
            }  
            return;
        }
        setTimeout(() => {
            countDown(waitTime,doSomethingDuringCountDown,doSomethingAfterCountDown);
        }, 1000);
}

例項

//DemoPage.jsx
import { countDown } from 'utils.js'

class DemoPage extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			time: '',
		};
	}
	componentDidMount = () => {
		countDown(5,this.waitTimeStateChange,this.linkTo);
    }

    waitTimeStateChange = (time) => {
        this.setState({
            time: time,
        })
    }
    linkTo = () => {
        history.push(ToBeReviewedShowData.linkUrl)
    }	
	render() {
		todoInfo = this.state.time + '秒後跳轉至登入介面'
		return (
			<div>
				todoInfo
			</div>
		)
	}
}
export default DemoPage