解決React首屏加載白屏的問題


眾所周知,在項目中如果在資源加載請求還未完成的時候,由於阻塞機制,會出現首頁白屏的問題,產生很差的用戶體驗。本文以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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM