在组件中加载初始数据时,如何在 react-transition-group 中暂停动画?
How could you pause animation in react-transition-group while loading initial data in components?
我有以下 App 组件:
<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
变量。另外,我不想在应用启动时预加载商店中的所有数据。
所以我的案例有点不同,但它们可能会帮助您想到解决方案。
- 您可以通过在整个路由器周围添加一个
if (this.state.isloaded == true)
块来轻松延迟初始显示。当你的组件挂载时开始加载,当异步调用完成时,setState({isloaded: true})
.
- 您可以制作自己的
<Link>
组件,它会启动一个请求,并且只有在它完成后才会更改页面位置。在此期间,您可以做任何您喜欢的特殊加载微调器。
基本上,将路由和转换组件保持在一侧。我发现他们在处理这种情况时会变得脆弱和痛苦。如果您需要更多详细信息或片段,请告诉我。
我已经通过 redux
和 redux-saga
完成了加载。也许这是使用 react-router
和 react-transition-group
实现跟随的唯一方法,因为在渲染方法为 运行 时随时切换动画,即使它 return 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;
}
}
最气人的是reducer chain——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 的复杂性,但它没有这样的工具来停止过渡。因此,它是实现预置数据转换的最佳方式之一。
我会让你的组件在加载时 return 为空,并让加载状态确定 CSSTransition 键,如 <CSSTransition key={location.key+loading?'-loading':''}
参见此处示例:https://stackblitz.com/edit/react-anim-route-once
请注意,为了不重复地完成这项工作,我必须让组件复制 loading 属性并将其保持在状态中,这样组件的副本之一就不会显示(这会创建组件的副本作为在这里看到: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;
}
}
我有以下 App 组件:
<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
变量。另外,我不想在应用启动时预加载商店中的所有数据。
所以我的案例有点不同,但它们可能会帮助您想到解决方案。
- 您可以通过在整个路由器周围添加一个
if (this.state.isloaded == true)
块来轻松延迟初始显示。当你的组件挂载时开始加载,当异步调用完成时,setState({isloaded: true})
. - 您可以制作自己的
<Link>
组件,它会启动一个请求,并且只有在它完成后才会更改页面位置。在此期间,您可以做任何您喜欢的特殊加载微调器。
基本上,将路由和转换组件保持在一侧。我发现他们在处理这种情况时会变得脆弱和痛苦。如果您需要更多详细信息或片段,请告诉我。
我已经通过 redux
和 redux-saga
完成了加载。也许这是使用 react-router
和 react-transition-group
实现跟随的唯一方法,因为在渲染方法为 运行 时随时切换动画,即使它 return 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;
}
}
最气人的是reducer chain——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 的复杂性,但它没有这样的工具来停止过渡。因此,它是实现预置数据转换的最佳方式之一。
我会让你的组件在加载时 return 为空,并让加载状态确定 CSSTransition 键,如 <CSSTransition key={location.key+loading?'-loading':''}
参见此处示例:https://stackblitz.com/edit/react-anim-route-once
请注意,为了不重复地完成这项工作,我必须让组件复制 loading 属性并将其保持在状态中,这样组件的副本之一就不会显示(这会创建组件的副本作为在这里看到: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;
}
}