在组件中加载初始数据时,如何在 react-transition-group 中暂停动画?

Posted

技术标签:

【中文标题】在组件中加载初始数据时,如何在 react-transition-group 中暂停动画?【英文标题】:How could you pause animation in react-transition-group while loading initial data in components? 【发布时间】:2019-04-28 02:11:43 【问题描述】:

我有以下应用组件:

            <Route render=(  location  ) => (
                <TransitionGroup component="div" className="content">
                    <CSSTransition key=location.key classNames="slide" timeout=
                        enter: 1000,
                        exit: 300
                     appear>
                        <Switch location=location>
                            <Route exact path='/' component=Intro/>
                            <Route path="/history" component=History/>
                            <Route path="/rules" component=Rules/>
                            <Route path="/faq" component=Faq/>
                            <Route path="/feedback" component=Feedback/>
                            <Route path="/partners" component=Partners/>
                        </Switch>
                    </CSSTransition>
                </TransitionGroup>
            )/>

它运行良好,但每个动画都会立即执行。例如,如果我从/rules 转到/history,我会在两个组件上获得完整的动画,但历史组件需要来自服务器的数据,因此动画应用于空容器。

如何在 react-transition-group 组件中暂停动画?我有 Redux,所以我可以在我的应用程序的任何地方更改 loading 变量。另外,我不想在应用启动时预加载商店中的所有数据。

【问题讨论】:

何时为新容器获取数据,是否在 componentWillMount 上? @RohitGarg 是的,我试过了。但这并不能解决这个问题,因为获取数据是 Promise(axios 如果这很重要),所以render() 将在完成数据加载之前被触发,因此它将触发来自react-transition-group 的动画,并在一段时间后出现数据屏幕。 【参考方案1】:

我会让你的组件在加载时返回 null 并让加载状态确定 CSSTransition 键,如 &lt;CSSTransition key=location.key+loading?'-loading':''

在此处查看示例:https://stackblitz.com/edit/react-anim-route-once

请注意,要使这项工作不重复,我必须使组件复制加载道具并将其保持在状态中,以便组件的副本之一永远不会显示(这将创建组件的副本,如此处所示:https://stackblitz.com/edit/react-anim-route-twice)

    <Route render=( location ) => (
      <TransitionGroup component="div" className="content">
        <CSSTransition key=location.key+(this.state.loading?'-loading':'-loaded') classNames="crossFade" timeout=
          enter: 3000,
          exit: 3000
         appear>
          <Switch location=location >
            <Route exact path='/' component=Hello />
            <Route exact path='/history' render=() =>
              <Delayed setLoading=this.handleSetLoading loading=this.state.loading /> />

          </Switch>

        </CSSTransition>
      </TransitionGroup>
    ) />

在组件中是这样的:

export default class History extends React.Component 
  state=loading:this.props.loading
  componentDidMount() 
    setTimeout(() => 
      this.props.setLoading(false);
    , 2000);
  
  render() 
    return !this.state.loading ? <div><h1>History! <Link to="/">Home</Link></h1></div> : null;
  

【讨论】:

不知道这对我有什么帮助。我应该用CSSTransition 包装每条路线还是将它放在每个组件中?我试图在组件的渲染中返回null,但它只是渲染前一个组件的进入/退出动画和null。因此,当数据准备好时,它只会呈现页面。 它确实有效,因为设置 CSSTransition 键使它在加载完成时假定另一个转换,但它有一个小缺陷,使加载的路线出现两次。我正在编辑以包含指向工作代码的链接(有这个缺陷,也有修复) 这个加载行为可以被提取到一个 HOC 以保持真正的组件和路由干净 我没有时间测试它,因为我使用了 redux 预加载,但我认为我应该给你赏金,因为它仅使用 react-transition-group 和 react-router 解决动画任务。 另外,渲染后它的工作有点奇怪。如果您第一次按 Home > History,它将完美运行,但当您按 History > Home 时,它​​会同时渲染两个组件。我们已经在我们的项目中解决了这样的问题,但对于这个例子来说,它仍然可以是一个小的改进。【参考方案2】:

所以我的案例有点不同,但它们可能会帮助你想出解决方案。

    您可以通过在整个路由器周围添加if (this.state.isloaded == true) 块来轻松延迟初始显示。在您的组件挂载和异步调用完成时开始加载,setState(isloaded: true)。 您可以创建自己的&lt;Link&gt; 组件,该组件会启动请求,并且只有在完成后才会更改页面位置。在此期间,您可以做任何您喜欢的特殊加载微调器。

基本上,将路由和过渡组件保持在一侧。我发现它们在这样的情况下变得脆弱和痛苦。如果您需要更多详细信息或 sn-ps,请告诉我。

【讨论】:

第一种方法不是一个选项,因为它会删除当前页面,因此在加载过程中将不可见。第二个选项更好,但是我可以在 Redux 中创建自定义重定向方法,而不是 Link 组件,我想要一些不同的东西。 Re 1,您可以让其他页面响应第一个选项中的第二个标志。它基本上是在构建你自己的状态管理器,这可能是地狱,但是 CSS 转换框架对 React Router 非常挑剔,所以我认为这是一个很好的技能。链接选项似乎更容易 tbh,如果您确实将其作为组件,您可以很好地封装它的状态和数据有效负载,并通过道具和状态上下传递它的存在。但是,我来自 iOS 领域,我对如何做事有奇怪的想法。【参考方案3】:

我已经通过 reduxredux-saga 完成了 peloading。也许这是使用react-routerreact-transition-group 实现跟随的唯一方法,因为在渲染方法运行时随时切换切换动画,即使它返回null。

我已经执行了以下操作:

const LoadingActions = 
    START_LOADING: 'START_LOADING',
    STOP_LOADING: 'STOP_LOADING',
    REDIRECT: 'REDIRECT',

    startLoading: () => (
        type: LoadingActions.START_LOADING
    ),

    stopLoading: () => (
        type: LoadingActions.STOP_LOADING
    ),

    redirect: ( url, token ) => (
        type: LoadingActions.REDIRECT,
        payload: 
            url,
            token
        
    )
;

export default LoadingActions;

在减速器中,我实现了简单的加载器减速器,它将打开和关闭加载变量:

import  LoadingActions  from "../actions";

const INITIAL_STATE = 
    loading: false
;

export default function ( state = INITIAL_STATE,  type  ) 
    switch ( type ) 
        case LoadingActions.START_LOADING:
            return  loading: true ;
        case LoadingActions.STOP_LOADING:
            return  loading: false ;
        default:
            return state;
    

最烦人的是减速链——this.props.loader.loading。对于这么简单的事情来说太复杂了。

import  combineReducers  from "redux";
...
import LoadingReducer from './LoadingReducer';

export default combineReducers( 
    ...
    loader: LoadingReducer
 );

大部分工作都在传奇中:

function* redirect ( action ) 
    yield put( LoadingActions.startLoading() );
    const  url  = action.payload;

    switch ( url ) 
        case MENU_URL.EXCHANGE:
            yield call( getExchangeData, action );
            break;
        ... other urls...
    
    yield put( LoadingActions.stopLoading() );
    BrowserHistory.push( url );


... loaders ...


function* watchRedirect () 
    yield takeLatest( LoadingActions.REDIRECT, redirect );


const sagas = all( [
    ...
    fork( watchRedirect )
] );

export default sagas;

我把监听器放在重定向动作上,所以它会调用重定向生成器。它将开始加载并调用数据预加载yield call 将等待预加载完成,然后停止加载和重定向。虽然它不会等待肯定的结果,但预加载器应该自己处理错误。

我希望我可以通过路由器或转换库的内置功能避免 redux 复杂性,但它没有这样的工具来停止转换。因此,它是使用预加载数据实现过渡的最佳方式之一。

【讨论】:

以上是关于在组件中加载初始数据时,如何在 react-transition-group 中暂停动画?的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Boot 应用程序上使用 Flyway 时如何在 H2 中加载初始数据?

如何在页面加载时调度 redux 操作以在 useEffect 中加载数据

如何在 MongoDB 中加载初始数据?

Reactjs - 如何在 reactjs 材料表中加载和映射数据

在 H2 中初始化数据时从文件中加载数据

如何通过Spring Boot在MongoDB中加载初始数据?