【问题标题】:React loading screen using hooks使用钩子反应加载屏幕
【发布时间】:2021-07-07 21:47:29
【问题描述】:

我正在 React 中构建一个应用程序,在其中我在 onClick 事件处理程序中获取播放列表数据。因为获取数据需要一些时间,所以我想显示一个加载屏幕。目前我正在将加载状态初始化为 true 并使其为 false 获取完成。但是,由于 Promise 中的代码是异步运行的,因此在完成获取数据之前,加载状态会更改为 false。我相信我可以为此使用 useEffect 但我不确定如何。我一直在寻找一个例子,但找不到一个,所以我来到这里。

const [isLoading, setIsLoading] = useState(true)
const history = useHistory()

const fetchPlaylist = (playlistId) => {  
    setIsLoading(true)
    fetch('/spotify/get-tracks-data', {headers: {
        'id': playlistId
    }})
    .then(response => response.json())
    .then(data => {
      history.push({pathname: `playlists/${playlistId}`, data})
      setIsLoading(false)
    })
  }

【问题讨论】:

  • fetchPlaylist 在哪里调用?在 Promise 链完成之前,您在哪里将加载状态更新为 false?你想用路由转换做什么?这可能会卸载运行此代码 sn-p 的组件,您可能会看到与“...更新卸载状态...”相关的错误。
  • fetchPlaylist 在与 onClick={() => fetchPlaylist(id)} 不同的组件中被调用。在我初始化其他状态(例如 userData)的 useEffect 挂钩中,我在此代码 sn-p 之前将加载状态更新为 false。我调用 history.push 将用户路由到新屏幕,同时传递获取的数据。然后在新屏幕中,数据被另一个组件使用。
  • useEffect 回调和这个fetchPlaylist 回调不会同时运行。您能否提供包含所有相关组件的Minimal, Complete, and Reproducible Code Example
  • 我相信 setIsLoading(false) 在这里没有用,因为您重定向到另一个页面。如果要在两个页面之间进行任何加载转换,则需要构建一个全局加载器。您当前的加载处于本地状态,因此它只能用作获取加载器,useEffect 在重定向到新页面之前适用于这种情况。一旦重定向,加载程序将立即为cut offfade out,具体取决于您的实现。
  • Lifting State Up 涵盖了一般模式。您可以在渲染路由器的组件中定义状态并向下传递 props,使用 React Context API,或移动到像 react-redux 这样的全局应用状态管理库。

标签: reactjs react-hooks


【解决方案1】:

所以最后,就像 Drew 建议的那样,我 lifted the loading state up 并将 Router 组件包装在一个名为“Loading”的高阶组件中,如下所示:

import {
    BrowserRouter as Router
  } from "react-router-dom";
import App from '../App';
import { useState, useEffect } from 'react';

const Loading = () => {

    const [loading, setLoading] = useState(true)

    const showLoading = () => (
        setLoading(true)
    )

    const hideLoading = () => (
        setLoading(false)
    )

    useEffect(() => {
        console.log(loading)
    }, [loading])

    return(
        <Router>
            <App loading={loading} showLoading={() => showLoading()} hideLoading={() => hideLoading()}/>
        </Router>
    )
}

export default Loading

然后我在 App 组件中的 fetchPlaylist 函数变成了这样:

const fetchPlaylist = (playlistId) => {  
showLoading()
fetch('/spotify/get-tracks-data', {headers: {
    'id': playlistId
}})
.then(response => response.json())
.then(data => {
  history.push({pathname: `playlists/${playlistId}`, data})
  hideLoading()
})

我很有信心这不是最干净的方法,但它确实有效......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-24
    • 1970-01-01
    • 2021-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多