【发布时间】:2018-03-07 16:23:25
【问题描述】:
我刚刚更新到 react native 0.54.0,其中还包括 react 16.3 的 alpha 1,我自然会收到很多关于 componentWillMount 和 componentWillReceiveProps 贬值的警告。
我有一个动画路线组件,它的核心依赖于 componentWillReceiveProps,它接收新路径,将其与前一个路径进行比较,如果它们是旧的子节点,则将它们设置为动画,设置新的子节点并为其添加动画。
这是有问题的代码:
componentWillReceiveProps(nextProps: Props) {
if (nextProps.pathname !== this.props.pathname) {
this.setState({ previousChildren: this.props.children, pointerEvents: false }, () =>
this.animate(0)
);
}
}
现在我有关于将其移植到static getDerivedStateFromProps的问题
1) 我不再可以访问this.props,因此无法访问以前的路径名,我想我可以将这些道具存储在状态中,现在这是正确的方法吗?好像是重复数据。
2) 由于我无法访问this,因此我无法调用我的动画函数,它依赖于状态。我怎样才能绕过这个?
3) 我需要先设置状态然后调用动画,因为getDerivedStateFromProps 通过返回值来设置状态,之后我不能做太多事情,所以有没有办法设置状态,然后执行回调?
4) pathname 位现在仅在 componentWillreceiveProps 中使用,如果我将其移动到状态并且从不在 getDerivedStateFromProps 内使用 this.state (因为我不能)this.state.pathname 错误被定义但没用过。最好的方法是让它成为静态吗?
我的第一反应是将其更改为componentDidUpdate,但我们不应该在其中使用setState,对吗? (这在我的场景中确实有效)。
componentDidUpdate(prevProps: Props) {
if (this.props.pathname !== prevProps.pathname) {
this.setState({ previousChildren: prevProps.children, pointerEvents: false }, () =>
this.animate(0)
);
}
}
注意:据我所知,我认为“悬念”中有一个功能可以让我们在组件卸载事件中保持安装视图?我找不到对此的任何参考,但听起来我可以在此动画中使用它
对于任何感兴趣的人,这是一个完整组件的 sn-p
// @flow
import React, { Component, type Node } from "react";
import { Animated } from "react-native";
type Props = {
pathname: string,
children: Node
};
type State = {
animation: Animated.Value,
previousChildren: Node,
pointerEvents: boolean
};
class OnboardingRouteAnomation extends Component<Props, State> {
state = {
animation: new Animated.Value(1),
previousChildren: null,
pointerEvents: true
};
componentWillReceiveProps(nextProps: Props) {
if (nextProps.pathname !== this.props.pathname) {
this.setState({ previousChildren: this.props.children, pointerEvents: false }, () =>
this.animate(0)
);
}
}
animate = (value: 0 | 1) => {
Animated.timing(this.state.animation, {
toValue: value,
duration: 150
}).start(() => this.animationLogic(value));
};
animationLogic = (value: 0 | 1) => {
if (value === 0) {
this.setState({ previousChildren: null, pointerEvents: true }, () => this.animate(1));
}
};
render() {
const { animation, previousChildren, pointerEvents } = this.state;
const { children } = this.props;
return (
<Animated.View
pointerEvents={pointerEvents ? "auto" : "none"}
style={{
alignItems: "center",
opacity: animation.interpolate({ inputRange: [0, 1], outputRange: [0, 1] }),
transform: [
{
scale: animation.interpolate({ inputRange: [0, 1], outputRange: [0.94, 1] })
}
]
}}
>
{previousChildren || children}
</Animated.View>
);
}
}
export default OnboardingRouteAnomation;
【问题讨论】:
-
我也一直在努力解决这个问题,但实际上我认为您找到的解决方案 (
componentDidUpdate()) 是正确的。实际上,在componentDidUpdate()中调用setState()是可以的——作为React 贡献者said himself。这将允许您使用动画回调。总的来说,我认为 React 团队正在推动我们采用更纯粹、更实用的方法,将副作用排除在渲染流程之外。 -
@LeedsEbooks 有趣的是,我还没有找到更好的方法,正在考虑在这个问题上增加赏金以吸引更多关注,看看是否有人有更好的建议。
标签: javascript reactjs react-native