【发布时间】:2017-08-24 19:06:57
【问题描述】:
在或多或少完成了我的第一个 React+Redux 应用程序之后,我已经到了想将动画应用到应用程序的各个部分的地步。查看现有解决方案,我发现没有什么比我想要的更接近。整个ReactCSSTransitionGroup 似乎是处理动画的一种侵入性和幼稚的方式。动画问题从您想要动画的组件中流出,您无法知道应用程序中发生的任何事情。根据我的初步分析,我提出了以下要求,我认为这是一个好的动画 API:
- 父组件应该不知道子组件如何淡入/淡出(可能除了交错动画)。
- 动画应与 React 集成,以便组件在被移除之前可以淡出(或以其他方式完成动画)。
- 应该可以在不修改组件的情况下将动画应用于组件。组件的样式可以与动画兼容,但不应有与动画相关的道具、状态、上下文或组件,也不应由动画决定组件的创建方式。
- 应该可以根据动作和应用程序状态执行动画 - 换句话说,当我拥有所发生事情的完整语义上下文时。例如,我可能会在创建事物时淡入组件,但不会在页面加载其中的项目时淡入淡出。或者,我可能会根据用户的设置选择适当的淡出动画。
- 应该可以为组件加入或组合动画。
- 应该可以将动画与父组件排入队列。例如,如果一个组件有两个子组件,打开一个会先触发另一个关闭,然后再打开。
入队动画的细节可以由现有的动画库处理,但应该可以将其与 react 和 redux 系统结合起来。
我尝试过的一种方法是创建一个这样的装饰器函数(它是 TypeScript,但我认为这对问题没有太大影响):
export function slideDown<T>(Component: T) {
return class FadesUp extends React.Component<any, any> {
private options = { duration: 0.3 };
public componentWillEnter (callback) {
const el = findDOMNode(this).childNodes[0] as Element;
if (!el.classList.contains("animated-element")) {
el.classList.add("animated-element");
}
TweenLite.set(el, { y: -el.clientHeight });
TweenLite.to(el, this.options.duration, {y: 0, ease: Cubic.easeIn, onComplete: callback });
}
public componentWillLeave (callback) {
const el = findDOMNode(this).childNodes[0] as Element;
if (!el.classList.contains("animated-element")) {
el.classList.add("animated-element");
}
TweenLite.to(el, this.options.duration, {y: -el.clientHeight, ease: Cubic.easeIn, onComplete: callback});
}
public render () {
const Comp = Component as any;
return <div style={{ overflow: "hidden", padding: 5, paddingTop: 0}}><Comp ref="child" {...this.props} /></div>;
}
} as any;
}
...可以这样应用...
@popIn
export class Term extends React.PureComponent<ITermStateProps & ITermDispatchProps, void> {
public render(): JSX.Element {
const { term, isSelected, onSelectTerm } = this.props;
return <ListItem rightIcon={<PendingReviewIndicator termId={term.id} />} style={isSelected ? { backgroundColor: "#ddd" } : {}} onClick={onSelectTerm}>{term.canonicalName}</ListItem>;
}
}
不幸的是,它要求将组件定义为一个类,但它确实可以在不修改组件的情况下以声明方式向组件添加动画。我喜欢这种方法,但讨厌我必须将组件包装在一个转换组中 - 它也没有解决任何其他要求。
我对 React 和 Redux 的内部和扩展点了解不多,无法很好地了解如何解决这个问题。我认为 thunk 动作将是管理动画流的好地方,但我不想将动作组件发送到动作中。相反,我希望能够检索一个动作或类似的东西的源组件。另一个角度可能是一个专门的 reducer,它同时传入动作和源组件,允许您以某种方式匹配它们并安排动画。
所以我想我所追求的是以下一项或多项:
- 挂钩到 React 和/或 Redux 的方法,最好不破坏性能或违反库的基本假设。
- 是否有任何现有的库可以解决部分或全部这些问题并且易于集成到应用程序中。
- 通过使用普通动画工具或很好地集成到普通构建块中来实现所有或大部分目标的技术或方法。
【问题讨论】:
标签: javascript reactjs animation redux