【问题标题】:static getDerivedStateFromProps that requires previous props and state callback?需要以前的道具和状态回调的静态 getDerivedStateFromProps?
【发布时间】:2018-03-07 16:23:25
【问题描述】:

我刚刚更新到 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,因此无法访问以前的路径名,我想我可以将这些道具存储在状态中,现在这是正确的方法吗?好像是重复数据。

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


【解决方案1】:

使用 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) 我不再有权访问 this.props,因此无法访问以前的路径名,我想我可以将这些 props 存储在 state 中。这是现在正确的方法吗?好像是重复数据。

是的。

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

看起来像是重复数据。

看看这个:React Team post on State and Lifecycle

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

Use componentDidUpdate

componentDidUpdate

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

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

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

参考第 2 点 (Use componentDidUpdate)

4) 路径名位现在仅在 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;

我相信这就是 react 开发者想要处理的方式。你应该 通过componentDidUpdate 更新后调用 animate,因为这是副作用。

我会使用更具描述性的名称来指示路径已更改。像isPathUpdated 这样的东西。然后您可以将animate 选中isPathUpdated 作为切换开关。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-08
    • 1970-01-01
    相关资源
    最近更新 更多