【问题标题】:Navigation Experimental is unmounting TabsNavigation Experimental 正在卸载标签
【发布时间】:2016-12-24 18:06:05
【问题描述】:

我正在开发一个反应原生应用程序,它使用复合实验导航(CardStack + Tabs)和 redux 进行状态管理。我能够创建基于选项卡的导航,但我现在面临的问题是当我在选项卡之间切换时,组件被卸载并且每次都重新渲染。

问题

假设我已经向下滚动了几篇文章,当我更改 Tab 时,它将从顶部开始。 (解决方法可能是将滚动位置存储在 redux 状态)。

这是我用于导航的示例代码Tabbed Experimental Navigation

【问题讨论】:

  • 我用过 NavigationIOS 和 TabBarIOS。在选项卡之间切换时组件不会卸载。

标签: javascript reactjs navigation react-native


【解决方案1】:

您必须更改 TabBar 的方法。

基本上,您希望每个选项卡都有导航器,因此您可以为每个选项卡设置路由堆栈,并使用一个导航器来包含选项卡(TabBar)。您还想为 TabBar 设置初始路由堆栈并在这些路由之间跳转。

了解 Navigator 方法之间的区别很重要。

  • 当你 pop 路由时,它被卸载,并且活动索引被移动到 最后一个。由于最后一个保持状态,它将恢复原样 以前渲染的(很可能,它可能发生道具改变)。再次转到popped 路线将完全重新渲染场景(这发生在您身上)。

  • 当你 push 路由时,没有卸载任何东西,新路由已安装。

  • 当你 jumpToIndex 路由时,再次卸载,因此跳转
    在路线之间恢复场景原样(再次,如果道具改变 场景将被重新渲染)。

所以,我认为这是不正确的:

我能够创建基于选项卡的导航,但我现在面临的问题是当我在选项卡之间切换时,组件被卸载并且每次都重新渲染。

...您使用错误的导航操作卸载路由。

现在还有什么不同,NavigationCardStack 并没有真正创建它自己的状态,它是从外部传递的,这给了你很大的灵活性。还有一个好处是您可以将 Facebook 提供的 reducer 用于常见操作(例如 push、pop、jumpToIndex;它们是 Navigation Utils 的一部分)。

你有关于如何创建 navigationState 和它 reducers here 的完整示例,所以我不打算解释,只是想说明如何解决你的问题。

[UPDATE] 示例现在可以使用了!

import React from 'react';
import { NavigationExperimental, View, Text, StyleSheet } from 'react-native';

const {
  CardStack: NavigationCardStack,
  StateUtils: NavigationStateUtils,
} = NavigationExperimental;

const style = StyleSheet.create({
  screen: {
    flex: 1,
  },
  screenTitle: {
    marginTop: 50,
    fontSize: 18,
  },
  pushNewScreenLabel: {
    marginVertical: 10,
    fontSize: 15,
    fontWeight: "bold",
  },
  goBackLabel: {
    fontSize: 15,
  },
  tabBarWrapper: {
    position: 'absolute',
    height: 50,
    bottom: 0,
    left: 0,
    right: 0,
    top: null,
    backgroundColor: 'grey',
    flexDirection: 'row',
    flex: 0,
    alignItems: 'stretch',
  },
  tabBarItem: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: 'red',
  },
});

export class TabBar extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.jumpToTab = this.jumpToTab.bind(this);

    // Create state
    this.state = {
      navigationState: {
        // Active route, will  be rendered as default
        index: 0,
        // "tab-s" represents route objects
        routes: [
          { name: 'Tab1', key: '1' },
          { name: 'Tab2', key: '2' },
          { name: 'Tab3', key: '3' },
          { name: 'Tab4', key: '4' }],
      },
    };
  }

  jumpToTab(tabIndex) {
    const navigationState = NavigationStateUtils.jumpToIndex(this.state.navigationState, tabIndex);
    this.setState({ navigationState });
  }

  renderScene({ scene }) {
    return <Tab tab={scene.route} />;
  }

  render() {
    const { navigationState } = this.state;
    return (
      <View style={style.screen}>
        <NavigationCardStack
          onNavigate={() => {}}
          navigationState={navigationState}
          renderScene={this.renderScene}
        />
        <View style={style.tabBarWrapper}>
          {navigationState.routes.map((route, index) => (
            <TabBarItem
              key={index}
              onPress={this.jumpToTab}
              title={route.name}
              index={index}
            />
            ))}
        </View>
      </View>
    );
  }
}

class TabBarItem extends React.Component {
  static propTypes = {
    title: React.PropTypes.string,
    onPress: React.PropTypes.func,
    index: React.PropTypes.number,
  }

  constructor(props, context) {
    super(props, context);
    this.onPress = this.onPress.bind(this);
  }
  onPress() {
    this.props.onPress(this.props.index);
  }
  render() {
    return (
      <Text style={style.tabBarItem} onPress={this.onPress}>
        {this.props.title}
      </Text>);
  }
}

class Tab extends React.Component {
  static propTypes = {
    tab: React.PropTypes.object,
  }

  constructor(props, context) {
    super(props, context);
    this.goBack = this.goBack.bind(this);
    this.pushRoute = this.pushRoute.bind(this);
    this.renderScene = this.renderScene.bind(this);
    this.state = {
      navigationState: {
        index: 0,
        routes: [{ key: '0' }],
      },
    };
  }

  // As in TabBar use NavigationUtils for this 2 methods
  goBack() {
    const navigationState = NavigationStateUtils.pop(this.state.navigationState);
    this.setState({ navigationState });
  }

  pushRoute(route) {
    const navigationState = NavigationStateUtils.push(this.state.navigationState, route);
    this.setState({ navigationState });
  }

  renderScene({ scene }) {
    return (
      <Screen
        goBack={this.goBack}
        goTo={this.pushRoute}
        tab={this.props.tab}
        screenKey={scene.route.key}
      />
    );
  }

  render() {
    return (
      <NavigationCardStack
        onNavigate={() => {}}
        navigationState={this.state.navigationState}
        renderScene={this.renderScene}
      />
    );
  }
}

class Screen extends React.Component {
  static propTypes = {
    goTo: React.PropTypes.func,
    goBack: React.PropTypes.func,
    screenKey: React.PropTypes.string,
    tab: React.PropTypes.object,
  }

  constructor(props, context) {
    super(props, context);
    this.nextScreen = this.nextScreen.bind(this);
  }

  nextScreen() {
    const { goTo, screenKey } = this.props;
    goTo({ key: `${parseInt(screenKey) + 1}` });
  }

  render() {
    const { tab, goBack, screenKey } = this.props;
    return (
      <View style={style.screen}>
        <Text style={style.screenTitle}>
          {`Tab ${tab.key} - Screen ${screenKey}`}
        </Text>
        <Text style={style.pushNewScreenLabel} onPress={this.nextScreen}>
          Push Screen into this Tab
        </Text>
        <Text style={style.goBackLabel} onPress={goBack}>
          Go back
        </Text>
      </View>
    );
  }
}
## TBD 多一点清理..

【讨论】:

  • 这正是我能够解决问题的方法。我所做的是为 4 个不同的选项卡渲染 4 个单独的 NavigationCardStack。在我对所有 4 个选项卡使用单个 CardStack 之前。因此,在更改选项卡时,导航减速器会改变状态,而 NavigatorCardStack 会重新渲染场景
  • @Nakib 你介意分享你的方法吗?我遇到了您在原始问题中描述的相同问题,并且每个标签使用导航器并没有为我解决。
  • @ElliottBorealis 我将代码更改为使用 TabBarIOS 并为每个选项卡单独设置卡片组。我不确定它是否可以在没有 TabBarIOS 的情况下工作
  • @Nakib 是的,我已经做过同样的事情,但希望可以在没有 TabBarIOS 的情况下完成。仅供参考,我一直在使用TabBarIOS 方法,但只有一个NavigationCardStack,它工作得很好。话虽如此,必须有一种方法可以仅使用NavigationExperimental 来实现TabBarIOS 选项卡切换体验,尤其是对于跨平台应用程序。
  • 今天晚些时候我会找时间创建工作示例,因为我认为这是实际的 :)
猜你喜欢
  • 2016-12-15
  • 1970-01-01
  • 1970-01-01
  • 2016-07-25
  • 1970-01-01
  • 2016-12-18
  • 2022-01-13
  • 2021-01-13
  • 2011-10-13
相关资源
最近更新 更多