眾所周知,在項目中如果在資源加載請求還未完成的時候,由於阻塞機制,會出現首頁白屏的問題,產生很差的用戶體驗。本文以react為例,提供一個解決方法。
解決原理:使用 onreadystatechange 去監聽 readyState,在資源加載完成之前加載一個只有框架的靜態頁面,頁面不請求數據。當數據請求完成之后再將路由切換到真實的首頁。
廢話不多說,上代碼:
main.js
import React from 'react'
import ReactDom from 'react-dom'
import {Provider} from 'react-redux'
import {BrowserRouter as Router, Route} from 'react-router-dom'
import configureStore from './store'
import Index from './containers/Index.js'
import FirstScreen from './containers/FirstScreen.js'
export const store = configureStore()
function listen () {
if (document.readyState == 'complete') { // 資源加載完成
ReactDom.render(
<Provider store={store}>
<Router>
<Route path="/" component={Index}/>
</Router>
</Provider>,
document.getElementById('root')
)
} else { // 資源加載中
ReactDom.render(
<Provider store={store}>
<Router>
<Route path="/" component={FirstScreen}/>
</Router>
</Provider>,
document.getElementById('root')
)
}
}
document.onreadystatechange = listen
其中Index.js就是你的真實首頁,FirstScreen.js就是只有框架的靜態頁。
Index.js
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import {store} from '../main'
import {bindActionCreators} from 'redux'
import {getLocalTime} from '../actions/localTime'
import LocalTime from '../components/LocalTime'
import '../static/css/Index.css'
class Index extends Component {
/**
* constructor() React組件的構造函數在掛載之前被調用。
* 在實現React.Component子類的構造函數時,
* 應該super(props)在任何其他語句之前調用。
* 否則,this.props會在構造函數中定義,這可能會導致錯誤。
*/
constructor (props) {
super(props)
this.realTime = this.realTime.bind(this)
}
realTime () {
setInterval(() => {
store.dispatch(getLocalTime())
}, 1000)
}
/**
* componentWillMount()會在組件render之前立即被調用,並且永遠都只執行一次。
* 由於這個方法始終只執行一次,所以如果在這里定義了setState方法之后,頁面永遠都只會在加載前更新一次。
*/
componentWillMount () {
}
/**
* componentDidMount()在組件被裝載后立即被調用。
* 在這個時候之后組件已經生成了對應的DOM結構。
* 可以在這個方法中執行setTimeout, setInterval,接口調用等。
*/
componentDidMount () {
this.realTime()
}
/**
* componentWillReceiveProps()在組件接收到一個新的prop時被執行。
* 這個方法在初始化render時不會被調用。
*/
componentWillReceiveProps () {
}
/**
* 返回一個布爾值。在組件接收到新的props或者state時被執行。
* 在初始化時或者使用forceUpdate時不被執行。
* 如果shouldComponentUpdate返回false,
* render()則會在下一個state change之前被完全跳過,componentWillUpdate和 componentDidUpdate也不會被執行
*/
shouldComponentUpdate (nextProps, nextState) {
return true
}
/**
* componentWillUpdate()在組件接收到新的props或者state但還沒有render時被執行。
* 在初始化時不會被執行。
*/
componentWillUpdate (nextProps, nextState) {
}
/**
* componentDidUpdate()在組件完成更新后立即執行。
* 在初始化時不會被執行。一般會在組件完成更新后被使用。
* 可以用來 clearInterval。
*/
componentDidUpdate (prevProps, prevState) {
clearInterval(this.realTime())
}
/**
* render()函數應該是純粹的,這意味着它不會修改組件狀態,
* 每次調用時都會返回相同的結果,並且不會直接與瀏覽器交互
*/
render () {
const {localTime} = this.props
return (
<div className='main'>
<LocalTime localTime={localTime} getLocalTime={getLocalTime}></LocalTime>
</div>
)
}
}
Index.propTypes = {
localTime: PropTypes.string,
getLocalTime: PropTypes.func
}
// 將state綁定到props
const mapStateToProps = (state, ownProps) => {
const {localTime} = state
return {
localTime: localTime.localTime
}
}
// 將action綁定到props上
const mapDispatchToProps = (dispatch, ownProps) => {
return {
getLocalTime: bindActionCreators(getLocalTime, dispatch)
}
}
// 通過react-redux提供的connect方法將我們需要的state中的數據和actions中的方法綁定到props上
export default connect(mapStateToProps, mapDispatchToProps)(Index)
FirstScreen.js
import React, {Component} from 'react'
import {connect} from 'react-redux'
import '../static/css/FirstScreen.css'
class FirstScreen extends Component {
constructor (props) {
super(props)
}
render () {
return (
<div className='firstScreen'>
我是首屏空白頁
</div>
)
}
}
export default connect()(FirstScreen)
本文轉載自:https://www.cnblogs.com/Man-Dream-Necessary/p/7994130.html