javascript 静态 getDerivedStateFromProps 需要先前的道具和状态回调?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/49156717/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
static getDerivedStateFromProps that requires previous props and state callback?
提问by Ilja
I have just updated to react native 0.54.0 that also includes alpha 1 of react 16.3, naturally I get a lot of warnings regarding depreciation of componentWillMountand componentWillReceiveProps.
我刚刚更新以响应本机 0.54.0,其中还包括 react 16.3 的 alpha 1,自然我收到了很多关于componentWillMount和折旧的警告componentWillReceiveProps。
I have an animated route component that was relying on componentWillReceivePropsat its core it receives new path, compares it to previous one, if they are sets old children, animates them out, sets new children and animates them in.
我有一个动画路由组件,componentWillReceiveProps它的核心依赖于它接收新路径,将其与前一个路径进行比较,如果它们设置了旧子项,则将它们设置为动画,设置新子项并为它们设置动画。
Here is code in question:
这是有问题的代码:
componentWillReceiveProps(nextProps: Props) {
if (nextProps.pathname !== this.props.pathname) {
this.setState({ previousChildren: this.props.children, pointerEvents: false }, () =>
this.animate(0)
);
}
}
Now for the questions I have regarding porting this to static getDerivedStateFromProps
现在对于我关于将其移植到的问题 static getDerivedStateFromProps
1) I no longer have access to this.props, hence no access to previous pathname, I guess I can store these props in state, is this correct approach now? Seems like repetition of data.
1)我不再有权访问this.props,因此无法访问以前的路径名,我想我可以将这些道具存储在状态中,现在这是正确的方法吗?好像是重复数据。
2) As I have no access to thisI can't call my animation function, that relies on a state. How can I bypass this?
2)由于我无法访问this我无法调用我的动画函数,这依赖于状态。我怎样才能绕过这个?
3) I need to first set state and then call the animation, as getDerivedStateFromPropssets state by returning the values, I can't do much afterwards, so is there a way to set state and after thats done execute a callback?
3)我需要先设置状态然后调用动画,作为getDerivedStateFromProps通过返回值设置状态,之后我不能做太多事情,那么有没有办法设置状态并在完成后执行回调?
4) pathnamebit is only used in componentWillreceivePropsright now, if I move it to state and never use this.stateinside getDerivedStateFromProps(because I can't) this.state.pathnameerrors as being defined but never used. Is the best approach here to make it static as well?
4) pathnamebit 只在componentWillreceiveProps现在使用,如果我将它移动到 state 并且从不使用this.state内部getDerivedStateFromProps(因为我不能)this.state.pathname错误被定义但从未使用过。这里也是使它静态的最佳方法吗?
My first instinct was to change it to componentDidUpdate, but we are not supposed to use setStateinside of it correct? (this does work in my scenario though).
我的第一直觉是把它改成componentDidUpdate,但我们不应该setState在它里面使用对吗?(虽然这在我的场景中确实有效)。
componentDidUpdate(prevProps: Props) {
if (this.props.pathname !== prevProps.pathname) {
this.setState({ previousChildren: prevProps.children, pointerEvents: false }, () =>
this.animate(0)
);
}
}
NOTE:As far as I heard I think there is a feature coming in "suspense" that will allow us to keep views mounted on component unmount event? I wasn't able to find any reference to this, but it sounds like something I could potentially utilise for this animation
注意:据我所知,我认为有一个“悬念”功能可以让我们在组件卸载事件上保持安装视图?我找不到对此的任何参考,但这听起来像是我可以用于此动画的潜在用途
For anyone interested, this is snippet for a full component in question
对于任何感兴趣的人,这是有问题的完整组件的片段
// @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;
回答by hendrathings
With react version 16.3, using componentWillReceivePropsis fine, but will cause a deprecation warning to be shown in the console. It will be removed in version 17. FWIW Dan Abramov has warned against using alpha functionality in production- but this was back in March of 2018.
使用 react 16.3 版,使用没问题componentWillReceiveProps,但会导致控制台中显示弃用警告。它将在版本 17 中删除。FWIW Dan Abramov 曾警告不要在生产中使用 alpha 功能——但这是在 2018 年 3 月。
Let's walk through your questions:
让我们来看看您的问题:
1) I no longer have access to this.props, hence no access to previous pathname, I guess I can store these props in state. Is this the correct approach now? Seems like repetition of data.
1)我不再可以访问this.props,因此无法访问以前的路径名,我想我可以将这些道具存储在状态中。这是现在正确的方法吗?好像是重复数据。
Yes.
是的。
If you want to update / re-render your component, you should combine propsand state. In your case, you want to update the component / trigger animation when pathnameis changed with a life cycle method.
如果你想更新/重新渲染你的组件,你应该结合props和state。在您的情况下,您希望在pathname使用生命周期方法更改时更新组件/触发器动画。
Seems like repetition of data.
好像是重复数据。
check this out: React Team post on State and Lifecycle
看看这个:React Team 关于状态和生命周期的帖子
2) As I have no access to this I can't call my animation function, which relies on state. How can I bypass this?
2)由于我无法访问它,因此无法调用依赖于状态的动画函数。我怎样才能绕过这个?
componentDidUpdate
This function will be called after render is finished in each of the re-render cycles. This means that you can be sure that the component and all its sub-components have properly rendered itself.
组件已更新
在每个重新渲染周期中渲染完成后将调用此函数。这意味着您可以确保组件及其所有子组件已正确呈现自身。
This means you can call animateafter setStatein componentDidUpdate
这意味着你可以调用animate后setState在componentDidUpdate
3) I need to first set state and then call the animation, as getDerivedStateFromProps sets state by returning the values, I can't do much afterwards, so is there a way to set state and after thats done execute a callback?
3)我需要先设置状态然后调用动画,因为 getDerivedStateFromProps 通过返回值来设置状态,之后我不能做太多事情,那么有没有办法设置状态并在完成后执行回调?
Refer to point #2 (Use componentDidUpdate)
请参阅第 2 点(使用 componentDidUpdate)
4) pathname bit is only used in componentWillreceiveProps right now, if I move it to state and never use this.state inside getDerivedStateFromProps (because I can't) this.state.pathname errors as being defined but never used. Is the best approach here to make it static as well?
4) pathname 位现在只在 componentWillreceiveProps 中使用,如果我将它移动到 state 并且从不在 getDerivedStateFromProps 中使用 this.state (因为我不能) this.state.pathname 错误被定义但从未使用过。这里也是使它静态的最佳方法吗?
No, It will used by componentDidUpdate
不,它会被 componentDidUpdate 使用
Here's how I would approach this:
这是我将如何处理这个问题:
// @flow
import React, { Component, type Node } from "react";
type Props = {
pathname: string,
children: Node
};
type State = {
previousChildren: Node,
pointerEvents: boolean
};
class OnboardingRouteAnomation extends Component<Props, State> {
state = {
previousChildren: null,
pointerEvents: true,
pathname: ''
};
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.pathname !== prevState.pathname) {
return {
previousChildren: nextProps.children,
pointerEvents: false,
pathname: nextProps.pathname
};
}
return null;
}
componentDidUpdate(prevProps, prevState) {
if (prevState.pathname !== this.state.pathname){
console.log("prevState.pathname", prevState.pathname);
console.log("this.props.pathname", this.props.pathname);
this.animate(0);
}
}
componentDidMount(){
this.setState({ pathname: this.props.pathname});
}
animate = (value: 0 | 1) => {
console.log("this animate called", 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 (
<div>
{this.props.children}
</div>
);
}
}
export default OnboardingRouteAnomation;
I believe this is how the react devs intended this should be handled. You should
call animate after updating via componentDidUpdatebecause it's a side effect.
我相信这就是反应开发人员打算如何处理的方式。你应该在更新之后调用 animate ,componentDidUpdate因为它是一个副作用。
I'd use a more descriptive name for indicating the path has changed. Something like isPathUpdated. You could then have animatecheck isPathUpdatedas a toggle.
我会使用更具描述性的名称来指示路径已更改。类似的东西isPathUpdated。然后,您可以将animate检查isPathUpdated作为切换。

