javascript - 需要以前的 Prop 和状态回调的静态 getDerivedStateFromProps?

标签 javascript reactjs react-native

我刚刚更新到 React Native 0.54.0,它还包括 React 16.3 的 alpha 1,自然地我收到了很多关于 componentWillMountcomponentWillReceiveProps 贬值的警告。

我有一个动画路由组件,其核心依赖于 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,因此无法访问以前的路径名,我想我可以将这些 Prop 存储在状态中,现在这是正确的方法吗?好像数据重复了。

2) 由于我无权访问 this 我无法调用依赖于状态的动画函数。我怎样才能绕过这个?

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

4) pathname 位现在只在 componentWillreceiveProps 中使用,如果我将它移动到 state 并且从不在 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)
      );
    }
  }

注意: 据我所知,我认为“suspense”中有一项功能允许我们在组件卸载事件时保持 View 挂载?我找不到对此的任何引用,但这听起来像是我可以用于此动画的东西

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

// @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;

最佳答案

对于 React 版本 16.3,使用 componentWillReceiveProps 没问题,但会导致在控制台中显示弃用警告。 It will be removed in version 17 . FWIW Dan Abramov has warned against using alpha functionality in production - 但这是在 2018 年 3 月。

让我们来看看你的问题:

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.

是的。

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

Seems like repetition of data.

检查一下:React Team post on State and Lifecycle

2) As I have no access to this I can't call my animation function, which relies on state. How can I bypass this?

Use componentDidUpdate

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.

这意味着您可以在 componentDidUpdate 中的 setState 之后调用 animate

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?

请参阅第 2 点(Use 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?

不,它会被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;

我相信这就是 React 开发人员希望处理的方式。你应该 在通过 componentDidUpdate 更新后调用 animate,因为这是一个副作用。

我会使用更具描述性的名称来指示路径已更改。类似于 isPathUpdated。然后,您可以让 animate 检查 isPathUpdated 作为切换。

关于javascript - 需要以前的 Prop 和状态回调的静态 getDerivedStateFromProps?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49156717/

相关文章:

javascript - 将带有前导零的颜色十六进制数字转换为字符串

javascript - 无法在 ReactJS 中显示图像?

react-native - 如何在 React Native 上构建 VoIP 应用程序?

IOS Testflight 即使在更新到新版本后也会加载我的应用程序的旧代码

javascript - Google Chrome 对我的 JS 代码没有响应?

javascript - 改变元素的类别,在每次鼠标点击

reactjs - 将 React hook 与 redux-saga(或任何其他中间件)结合使用

reactjs - 如何在 const 中使用 react 导航?

javascript - Raphael JS 饼图标签

reactjs - 在 React.js 中,使用 flexGrow 时得到错误的 clientHeight