关于loading:React-loading

17次阅读

共计 2904 个字符,预计需要花费 8 分钟才能阅读完成。

需要

家喻户晓,利用如果少了loading,交互就显得生硬。

本文分享如何在 React 中从零到一实现并应用loading

实现

一个 loading,应该始终呈现在 视口的正中

同时为了示意加载过程的动态性,须要适当的 动画

以及,胜利和失败的提醒与 loading 其实实质上是一回事,所以,实现 loading 的同时,也顺便将另外两个一并实现。

严格意义上,这是 toast 的实现。

Toast.jsx

import l from './toast.module.css'
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
import {faCheck, faSpinner, faTriangleExclamation} from '@fortawesome/pro-solid-svg-icons'
import PropTypes from 'prop-types'
import {memo} from 'react';

function Toast({type, message}) {
    return (<div className={l.toast} >
            <div className={l.container} >
                {
                    type === 'success'
                        ? <FontAwesomeIcon icon={faCheck} />
                        : type === 'fail'
                            ? <FontAwesomeIcon icon={faTriangleExclamation} />
                            : <FontAwesomeIcon icon={faSpinner} className={l.loading} />
                }
            </div>
            {
                message
                    ? message
                    : type === 'success'
                        ? '实现'
                        : type === 'fail'
                            ? '失败'
                            : '加载中'
            }
        </div>
    )
}

Toast.propTypes = {type: PropTypes.oneOf(['loading', 'success', 'fail']),
    message: PropTypes.string
}

export default memo(Toast)


toast.module.css

:root {
    --toastSize: 136px;
    --containerSize: 40px;
}

.toast {width: var(--toastSize);
    height: var(--toastSize);
    position: fixed;
    top: calc(50vh - var(--toastSize)/2);
    left: calc(50vw - var(--toastSize)/2);
    background: #4C4C4C;
    border-radius: 12px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, .9);
}

.container {width: var(--containerSize);
    display: inherit;
    flex-direction: inherit;
    align-items: inherit;
    margin: 0 auto 16px;
}

.container > svg {height: var(--containerSize);
}

.loading {animation: rotate linear 1s infinite;}

@keyframes rotate {
    from {transform: rotate(0);
    }
    to {transform: rotate(360deg);
    }
}

应用

路由

loading的首要利用场景就是页面间的切换。

应用 lazy()Suspense配合 React Router 实现页面间切换时新页面加载 loading 的显隐:

// App.jsx
import React, {Suspense, lazy} from 'react'
import {BrowserRouter, Routes, Route} from 'react-router-dom'

const Home = lazy(() => import('./routes/Home'))
const About = lazy(() => import('./routes/About'))

const App = () => (
    <Router>
        <Suspense fallback={<Toast/>}>
            <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/about" element={<About />} />
            </Routes>
        </Suspense>
    </Router>
);

不过,目前这个组合有一个 致命毛病

即新组件尚未实现加载时,旧组件曾经暗藏,且不论新组件加载得多快,Suspensefallback 都会执行,这将导致 页面切换时呈现闪动

尽管官网推出了 startTransition() 解决闪动问题,但该计划目前尚未实用于路由。

所以这个组合实际中不举荐应用,因为以页面闪动为代价实现 loading 得失相当。

过渡

React新增的 useTranstion() Hook,搭配useState(),实现动静组件加载时loading 的显隐。

import {useEffect, useState, useTransition} from 'react'
import {url} from '../../configuration'
import Toast from '../../../components/toast/Toast'
import Table from '../../../components/table/Table'

export default function User() {const [res, setRes] = useState({})
    const [loading, startTransition] = useTransition() // loading 示意过渡工作的期待状态

    useEffect(() => {fetch(`${url}`, {method: 'GET'})
            .then(r => r.json())
            .then(d => {if (d.hasOwnProperty('err'))
                    alert(`${d.text}:${d.err}`)
                else if (d.hasOwnProperty('data')
                )
                    startTransition(() => {setRes(d)}) // 将 setRes()标记为过渡工作})
            .catch(e => {alert(e)})
    }, [])

    return (
        <div>
            {loading && <Toast/>}
            <Table
                res={res}
            />
        </div>
    )
}

useTransition()简直能笼罩 loading 的绝大部分场景,因为在 React 中,组件的更新根本都是通过在 useEffect() 的依赖数组中增加 state 来实现。

总结

本着 官网反对的绝不本人再封装 的准则,loading的需要算是根本实现了,后续开发中若有新播种再来同步。

若有有余,欢送斧正。

正文完
 0