【问题标题】:react router preload data from multiple components with a single loader animation使用单个加载器动画反应路由器预加载来自多个组件的数据
【发布时间】:2021-07-27 16:56:04
【问题描述】:

我有一个应用需要具有动态标头,从获取请求中加载外部文件。

一旦用户登录,他们就会被定向到门户/portal。我已将布局定义为:

export const UserLayout = ({ children }) => <div><Header /><div className="body">{children}</div></div>

这包含一个包含动态链接的标题,然后允许路由通过,因此不会在每次页面更改时加载标题。

export const UserRoutes = () => {
  return (
    <UserLayout>
      <Switch> 
        <Route path="/portal" exact component={Portal}/>
        <Route path="/settings" exact component={Settings}/>
      </Switch>
    </UserLayout>
  );
}

/login 重定向到/portal 后首先加载标头。 我在 redux 中设置了一个全局加载器,它基本上在获取数据时显示全屏加载动画。

我遇到的主要问题是,如何在一个请求中加载我的应用程序的两个部分?

例如,header 加载 ajax 内容,显示 redux 加载动画,然后停止。然后路由加载,它也显示了一个 redux 加载动画,然后停止。这会产生闪烁效果。

同时拥有主要部分负载和子负载的最佳方法是什么?

【问题讨论】:

  • 没有代码很难确定。您可以创建带有虚假 API 请求的代码框,或者至少在您的帖子中包含更多代码以及整个生命周期如何触发加载动画?如何从 REDUX 触发加载动画?是由布尔值变化触发的吗?
  • 你的路由数据是否依赖于头部获取的数据?还是它们是两个不同的东西?并添加更多关于您的 api 调用和 redux 设置的代码,这将有助于为您提供正确的 sn-p 代码

标签: reactjs redux react-router-v4


【解决方案1】:

我不知道您的应用程序的结构如何,但这会给您一个想法。您可以将属性添加到您的 state 以控制待处理的请求。

const STATE = {
 requests: []
 ...
}

定义基本的actions(您可以添加更多请求取消等)。您需要知道请求何时开始以及何时结束:

const requestStartedAction = id => ({
  type: REQUEST_STARTED,
  payload: { id } //--> something to identify the request
});

const requestEndedAction = id => ({
  type: REQUEST_ENDED,
  payload: { id }
});

reducer

export default function(state = {}, action) {
  switch (action.type) {
    case REQUEST_STARTED:
      return {
        ...state,
        requests: [...state.requests, action.payload.id], //-> add a new request to the list
        loading: true,
      };
    case REQUEST_ENDED:
      const pendingRequests = state.requests.filter(id => id!== action.payload.id); //--> remove request from the list
      return {
        ...state,
        requests: pendingRequests,
        loading: !Boolean(pendingRequests.length), //--> don't hide the loading if there any request pending
       
      };
    
   ...
  }
}

然后,每次您发出请求时,您都会调用 requestStartedAction。当请求完成时,您可以调用 requestEndedAction。使用 fetch 的基本示例:

dispatch(requestStartedAction(ID));
fetch(URL).finally(() => dispatch(requestEndedAction(ID)));

如果请求列表为空,加载效果将停止。

【讨论】:

    【解决方案2】:

    你不需要任何 redux 这个...

    import {lazy, Suspense} from 'react'
    import {BrowserRouter, Switch, Route} from 'react-router-dom'
    
    import Loader from './path/to/loader'
    
    const Component1 = lazy(() => import('./path/to/component1')
    const Component2 = lazy(() => import('./path/to/component2')
    
    const Router = () => {
      <Suspense fallback={<Loader/>}>
        <BrowserRouter>
          <Switch>
            <Route path='/path1' component={Component1}/>
            <Route path='/path2' component={Component2}/>
          </Switch>
        </BrowserRouter>
      </Suspense>
    }
    

    如果这对您不起作用,那么您需要创建一个父级,该父级可以在渲染之前获取所需的所有数据并将其传递给子级,然后您可以在该父级中显示加载器。

    如果您让全局组件在每次进行 fetch 调用时管理加载,您最终会处理闪烁或双重加载级联效应。

    【讨论】:

      【解决方案3】:

      here is the project with redux and a single loading

      我做了一个加载减速器,如果需要获取数据,则在每个组件中,start-loading 被调度并将一个值推入加载数组,当数据被获取时,stop-loadig 被调度并从数组中弹出值.

      const LoadingReducer = (state = initState, action) => {
        const prevState = { ...state };
        switch (action.type) {
          case "START_LOADING":
            prevState.loading.push(true);
            return { ...state, prevState };
          case "STOP_LOADING":
            prevState.loading.pop(true);
            return { ...state, prevState };
          default:
            return state;
        }
      };
      

      App.js 中,我只是从商店获取加载并检查它是否有价值,然后决定是否显示Loader

      import { useEffect, useState } from "react";
      import { connect } from "react-redux";
      import UserRoutes from "./UserRoutes";
      import Loader from "./Loader";
      import "./styles.css";
      
      const App = (props) => {
        const [loading, setLoading] = useState(0);
        useEffect(() => {
          setLoading(props.loading);
        }, [props.loading]);
        return (
          <div className="App">
            {loading && <Loader />}
            <UserRoutes />
          </div>
        );
      };
      const mapStateToProps = (state) => {
        return {
          loading: state.LoadingReducer.loading.length > 0 ? true : false
        };
      };
      
      export default connect(mapStateToProps, null)(App);
      

      【讨论】:

        猜你喜欢
        • 2022-11-10
        • 1970-01-01
        • 1970-01-01
        • 2017-12-08
        • 2019-06-26
        • 2012-10-31
        • 2019-07-03
        • 2017-07-19
        • 1970-01-01
        相关资源
        最近更新 更多