static getDerivedStateFromProps需要先前的道具和状态回调吗?

Ilj*_*lja 11 javascript reactjs react-native

我刚刚更新,以反应原生0.54.0,其中还包括反应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)
      );
    }
  }
Run Code Online (Sandbox Code Playgroud)

现在我有关于将此移植到的问题 static getDerivedStateFromProps

1)我不再有权访问this.props,因此无法访问以前的路径名,我想我可以将这些道具存储在状态中,这是正确的方法吗?似乎重复数据.

2)因为我无法访问this我无法调用我的动画功能,这依赖于一个状态.我怎么能绕过这个?

3)我需要首先设置状态,然后调用动画,因为getDerivedStateFromProps通过返回值设置状态,之后我做不了多少,所以有没有办法设置状态,之后执行回调?

4)pathnamebit仅用于componentWillreceiveProps现在,如果我将其移动到状态并且从不使用this.state内部getDerivedStateFromProps(因为我不能)this.state.pathname错误定义但从未使用过.这里最好的方法是使它静止吗?

我的第一直觉是改变它componentDidUpdate,但我们不应该setState在它内部使用正确吗?(这在我的场景中确实有效).

  componentDidUpdate(prevProps: Props) {
    if (this.props.pathname !== prevProps.pathname) {
      this.setState({ previousChildren: prevProps.children, pointerEvents: false }, () =>
        this.animate(0)
      );
    }
  }
Run Code Online (Sandbox Code Playgroud)

注意:据我所知,我认为有一个功能出现在"悬疑"中,这将允许我们保持视图安装在组件卸载事件上?我无法找到任何参考,但这听起来像我可能用于这个动画的东西

对于任何感兴趣的人,这是一个有问题的完整组件的片段

// @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;
Run Code Online (Sandbox Code Playgroud)

hen*_*ngs 12

使用react版本16.3,使用componentWillReceiveProps正常,但会导致在控制台中显示弃用警告.它将在版本17中删除.FWIW Dan Abramov已警告不要在生产中使用alpha功能 - 但这是在2018年3月.

让我们来看看你的问题:

1)我不再能访问this.props,因此无法访问以前的路径名,我想我可以将这些道具存储在状态中.这是正确的方法吗?似乎重复数据.

是.

如果要更新/重新渲染组件,则应合并propsstate.在您的情况下,您希望在pathname使用生命周期方法更改时更新组件/触发器动画.

似乎重复数据.

检查一下:React Team发布状态和生命周期

2)因为我无法访问这个,所以我无法调用依赖于状态的动画功能.我怎么能绕过这个?

使用componentDidUpdate

componentDidUpdate

在每个重新渲染周期中完成渲染后,将调用此函数.这意味着您可以确保组件及其所有子组件已正确呈现.

这意味着你可以调用animatesetStatecomponentDidUpdate

3)我需要首先设置状态然后调用动画,因为getDerivedStateFromProps通过返回值设置状态,之后我做不了多少,所以有没有办法设置状态,之后执行回调?

请参阅第2点(使用componentDidUpdate)

4)pathname位目前仅在componentWillreceiveProps中使用,如果我将其移动到state并且从不在getDerivedStateFromProps中使用this.state(因为我不能)this.state.pathname错误被定义但从未使用过.这里最好的方法是使它静止吗?

不,它将由componentDidUpdate使用

这是我如何处理这个问题:

// @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;
Run Code Online (Sandbox Code Playgroud)

我相信这就是反应开发者应该如何处理的.您应该在更新后调用animate,componentDidUpdate因为它是副作用.

我将使用更具描述性的名称来指示路径已更改.有点像isPathUpdated.然后你可以animate检查isPathUpdated作为切换.