【问题标题】:React router native animation blinks before animation startsReact 路由器原生动画在动画开始前闪烁
【发布时间】:2018-03-02 22:06:59
【问题描述】:

我正在开发一个 react native 应用程序并使用 React router native v4,并且我正在尝试开发动画部分,正如文档所建议的那样,首先我确保一切都可以在没有动画或过渡的情况下正常工作。

我已经迭代了实现,这就是我现在所得到的:

我的主要组件呈现以下内容:

// app.js:render
<ConnectedRouter history={history}>
  <App />
</ConnectedRouter>

我的 routes.js 呈现以下内容(注意传递给 Switch 的 location 属性以防止它在父组件之前更新其子组件):

// routes.js render
<ViewTransition pathname={location.pathname}>
  <Switch location={location}>
    <Route exact path={uri.views.main} component={Dashboard} />
    <Route path={uri.views.login} component={Login} />
    <Route path={uri.views.register} component={Register} />
  </Switch>
</ViewTransition>

以及处理动画的 ViewTransition,现在它只是淡入/淡出旧视图和新视图:

// view-transition.js
@withRouter
export default class ViewTransition extends Component {
  static propTypes = {
    children: PropTypes.node,
    location: PropTypes.object.isRequired,
  };

  state = {
    prevChildren: null,
    opacity: new Animated.Value(1)
  };

  componentWillUpdate(nextProps) {
    if (nextProps.location !== this.props.location) {
      this.setState({ prevChildren: this.props.children }, this.animateFadeIn);
    }
  }

  animateFadeIn = () => {
    Animated.timing(this.state.opacity, {
      toValue: 0,
      duration: 150
    }).start(this.animateFadeOut);
  };

  animateFadeOut = () => {
    this.setState({ prevChildren: null }, () => {
      Animated.timing(this.state.opacity, {
        toValue: 1,
        duration: 400
      }).start();
    });
  };

  render() {
    const { children } = this.props;
    const { prevChildren, opacity } = this.state;
    return (
      <Animated.View
        style={{
          ...StyleSheet.absoluteFillObject,
          opacity,
          position: "absolute"
        }}
      >
        {prevChildren || children}
      </Animated.View>
    );
  }
}

上面的代码正在运行,我可以看到旧视图淡出,新视图淡入,但我有一个问题,当它开始淡出时,组件以某种方式再次重新安装,我可以在动画开始前看到闪烁,我想知道我的代码有什么问题。

【问题讨论】:

    标签: reactjs animation react-native react-router-v4 react-router-native


    【解决方案1】:

    我可以修复我上面的代码,碰巧在反应组件的生命周期中的方法 componentWillUpdate 已经将 nextProps 传递给了子组件,同时我的组件设置了旧子组件的新状态,Switch 是准备渲染新的,这会产生 oldChildren 的卸载和新子的 mount,当我的组件最终完成设置状态时,旧的子已经被卸载,它们必须再次安装。

    上面的故事是“我的动画开始时我可以看到眨眼”的长篇故事,解决方法很简单,我不再检查componentWillUpdate的东西,而是componentWillReceiveProps,因为新props 将在其子组件之前传递给父组件,它给了我足够的时间来捕获当前的子组件,将它们分配给状态,在 Switch 卸载它们之前渲染并将它们保留在视图中以淡出,因此不再闪烁。

    我的最终视图-transition.js:

    // view-transition.js
    export default class ViewTransition extends Component {
      static propTypes = {
        children: PropTypes.node,
        location: PropTypes.object.isRequired,
      };
    
      state = {
        prevChildren: null,
        opacity: new Animated.Value(1)
      };
    
      componentWillReceiveProps(nextProps) {
        if (nextProps.location !== this.props.location) {
          this.setState({ prevChildren: this.props.children }, this.animateFadeIn);
        }
      }
    
      animateFadeIn = () => {
        Animated.timing(this.state.opacity, {
          toValue: 0,
          duration: 150
        }).start(this.animateFadeOut);
      };
    
      animateFadeOut = () => {
        this.setState({ prevChildren: null }, () => {
          Animated.timing(this.state.opacity, {
            toValue: 1,
            duration: 400
          }).start();
        });
      };
    
      render() {
        const { children } = this.props;
        const { prevChildren, opacity } = this.state;
        return (
          <Animated.View
            style={{
              ...StyleSheet.absoluteFillObject,
              opacity,
              position: "absolute"
            }}
          >
            {prevChildren || children}
          </Animated.View>
        );
      }
    }
    

    【讨论】:

    • 我建议你不要在 react-native 中使用 react-router。让导航库处理转换。比如 react-navigation 或者 react-native-navigation。
    • @Noitidart 嘿!谢谢建议,我去看看
    • 我的荣幸哈维尔。我也做了类似的举动,后悔了。当我第一次接触 react-native 时,我非常喜欢 react-router v4,我也想在 native 中使用它。但是使用这些导航,我发现它非常适合平台感觉,而且是免费的,无需我自己实现任何动画。
    【解决方案2】:

    我写了一个 AnimatedSwitch 组件在 React Native 中工作。

    有一个短暂的时刻,状态正在更新并且它会闪烁,但我用这段代码修复了这个问题:

      // Need to render the previous route for the time between not animating and animating
      if (needsAnimation && !animating) {
        const tempPreviousRoute = getPreviousRoute(
          exact,
          previousLocation,
          previousChildren,
        );
    
        if (tempPreviousRoute) {
          const prevRouteComp = renderPreviousRoute(tempPreviousRoute);
          return prevRouteComp;
        } else {
          return null;
        }
      }

    完整的代码在这里。

    https://javascriptrambling.blogspot.com/2020/07/react-router-native-animatedswitch.html

    【讨论】:

      【解决方案3】:

      嗯..我知道有点晚了,也许你可以试试react-router-native-animate-stack

      它是react-router-native 的子组件。但它是可动画的并提供堆栈功能。它的灵感来自switch 组件,如果你知道switch,你就会知道如何使用这个包。

      Default behaviour

      Customization

      【讨论】:

      • 这不需要让用户返回 - 它也不会保存最后一个组件。它重新渲染它。
      猜你喜欢
      • 2017-10-21
      • 2019-04-15
      • 2019-10-02
      • 2019-04-06
      • 1970-01-01
      • 2011-12-02
      • 2012-03-12
      • 2011-03-30
      • 2011-08-23
      相关资源
      最近更新 更多