开发者问题收集

通过 DrawerNavigator 中的 StackNavigator 将数据从一个页面传递到另一个页面

2019-11-12
556

对于一个业余项目,我正在构建一个应用程序,我的朋友可以查看我们计划的小组活动。每当有人点击某个活动时,我都希望显示一个包含该特定活动详细信息的屏幕。因此,我想从显示带有事件的 FlatList 的 EventScreen 转到 EventDetailScreen。它需要显示一个特定事件。

到目前为止,我已经让导航部分正常工作,但我无法将任何数据传递到下一个屏幕...

我尝试过以多种方式将事件作为参数发送。但我不知道下一步该怎么做。我读过一些关于需要将数据从 DrawerNavigator 传递到 StackNavigator 的内容,但当我尝试这样做时,我收到一条错误消息,提示我需要在 AppContainer 中定义导航。

MenuNavigator.js

//Navigation Drawer Structure for all screen
class NavigationDrawerStructure extends Component {
  //Top Navigation Header with Donute Button
  toggleDrawer = () => {
    //Props to open/close the drawer
    this.props.navigationProps.toggleDrawer();
  };
  render() {
    return (
      <View style={{ flexDirection: 'row' }}>
        <TouchableOpacity onPress={this.toggleDrawer.bind(this)}>
          <Ionicons
            name="md-menu"
            color="white"
            size={32}
            style={styles.menuIcon}
          />
        </TouchableOpacity>
      </View>
    );
  }
}

//Stack Navigator for the First Option of Navigation Drawer
const HomeScreen_StackNavigator = createStackNavigator({
  //All the screen from the First Option will be indexed here
  HomeScreen: {
    screen: HomeScreen,
    navigationOptions: ({ navigation }) => ({
      headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
      headerStyle: {
        backgroundColor: '#000',
      },
    }),
  },
});

//Stack Navigator for the Second Option of Navigation Drawer
const EventsScreen_StackNavigator = createStackNavigator({
  //All the screen from the Second Option will be indexed here
  EventsScreen: {
    screen: EventsScreen,
    navigationOptions: ({ navigation }) => ({
      headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
      headerStyle: {
        backgroundColor: '#000',
      },
    }),
  },
});

//Stack Navigator for the Third Option of Navigation Drawer
const CalendarScreen_StackNavigator = createStackNavigator({
  //All the screen from the Third Option will be indexed here
  CalendarScreen: {
    screen: CalendarScreen,
    navigationOptions: ({ navigation }) => ({
      headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
      headerStyle: {
        backgroundColor: '#000',
      },
    }),
  },
});

//Stack Navigator for the Fourth Option of Navigation Drawer
const PollScreen_StackNavigator = createStackNavigator({
  //All the screen from the Third Option will be indexed here
  PollScreen: {
    screen: PollScreen,
    navigationOptions: ({ navigation }) => ({
      headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
      headerStyle: {
        backgroundColor: '#000',
      },
    }),
  },
});

//Stack Navigator for the Fifth Option of Navigation Drawer
const InfoScreen_StackNavigator = createStackNavigator({
  //All the screen from the Third Option will be indexed here
  InfoScreen: {
    screen: InfoScreen,
    navigationOptions: ({ navigation }) => ({
      headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
      headerStyle: {
        backgroundColor: '#000',
      },
    }),
  },
});

//Stack Navigator for the EventDetailScreen of Navigation Drawer
const EventDetailScreen_StackNavigator = createStackNavigator({
  //All the screen from the Third Option will be indexed here
  EventDetailScreen: {
    screen: EventDetailScreen,
    navigationOptions: ({ navigation }) => ({
      headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
      headerStyle: {
        backgroundColor: '#000',
      },
    }),
  },
});

const DrawerMenu = createDrawerNavigator(
  {
    HomeScreen: {
      screen: HomeScreen_StackNavigator,
    },
    EventsScreen: {
      screen: EventsScreen_StackNavigator,
    },
    CalendarScreen: {
      screen: CalendarScreen_StackNavigator,
    },
    PollScreen: {
      screen: PollScreen_StackNavigator,
    },
    InfoScreen: {
      screen: InfoScreen_StackNavigator,
    },
    EventDetailScreen: {
      screen: EventDetailScreen_StackNavigator,
    },
  },
  {
    // define customComponent here
    contentComponent: CustomSidebarMenu,
    drawerWidth: 300,
    drawerBackgroundColor: 'rgba(0,0,0,0.6)', // or 'rgba(0,0,0,0)'
  }
);

const styles = StyleSheet.create({
  menuIcon: {
    marginLeft: 15,
  },
});

export default createAppContainer(DrawerMenu);

Events.js

class EventsScreen extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLoading: true,
      dataSource: null,
      refreshing: false,
    };
  }

  async componentDidMount() {
    const events = await ajax.FetchEvents();
    this.setState({
      isLoading: false,
      dataSource: events,
      refreshing: false,
    });
  }

  handleRefresh = () => {
    this.setState(
      {
        refreshing: false,
      },
      () => {
        this.componentDidMount();
      }
    );
  };

  itemCard({ item }) {
    const { navigate } = this.props.navigation;
    return (
      <TouchableWithoutFeedback
        onPress={() =>
          navigate('EventDetailScreen', {
            data: 'test',
          })
        }>
        <View style={styles.card}>
          <View style={styles.item}>
            <Text style={styles.title}>{item.title}</Text>
            <Text numberOfLines={1} style={styles.desc}>
              {item.description}
            </Text>
            <View style={styles.row}>
              <View style={styles.iconColumn}>
                <Ionicons name="md-home" color="white" size={24} />
              </View>
              <View style={styles.textColumn}>
                <Text style={styles.location}>location</Text>
              </View>
            </View>
            <View style={styles.row}>
              <View style={styles.iconColumn}>
                <Ionicons name="md-calendar" color="white" size={24} />
              </View>
              <View style={styles.textColumn}>
                <Text style={styles.date}>{item.date}</Text>
              </View>
            </View>
          </View>
        </View>
      </TouchableWithoutFeedback>
    );
  }

  render() {
    if (this.state.isLoading) {
      return (
        <View style={styles.container}>
          <ActivityIndicator />
        </View>
      );
    } else {
      return (
        <View style={styles.container}>
          <FlatList
            data={this.state.dataSource}
            renderItem={({ item }) => this.itemCard({ item })}
            keyExtractor={item => item.id.toString()}
            onRefresh={() => this.handleRefresh()}
            refreshing={this.state.refreshing}
          />
        </View>
      );
    }
  }
}

EventDetailScreen.js

class EventDetailScreen extends Component {
  render() {
    let item = this.props.navigation.getParam('data', 'NO-DATA');

    return (
      <View>
        <Text>{item}</Text>
      </View>
    );
  }
}

export default EventDetailScreen;  

每当我单击某个事件时,EventDetailScreen 都会显示“NO-DATA”,因为该项目未定义。我的目的是将用户单击的事件传递到下一个屏幕。因此,我可以使用来自该特定事件的标题、描述等。

是的,我知道代码有点乱。我是 React-Native 的新手,这是我的第一个应用程序(也是第一篇文章),所以还有很多需要改进的地方 :)

提前谢谢您!

3个回答

我发现我应该使用 this.props.navigation.push 而不是 navigation。这样我就可以将参数传递到下一个屏幕。谢谢!

LarsB
2019-11-12

用于传递参数

this.props.navigation.navigate('Filter', {
        uri: this.state.uri,
    });

用于获取参数

  const { navigation } = this.props;

    const uri = navigation.getParam('uri');
    console.log('url', uri);
    this.setState({ uri: uri });
Rahul Jograna
2019-11-12

当您调用 setState() 时,它会重新渲染组件。当组件渲染时,它会调用组件的生命周期(例如 componentWillUpdatecomponentDidUpdate )。

您可能会收到错误,因为您可能在任何生命周期方法中设置状态。因此,它会创建递归函数调用,并且您会达到 超出最大更新深度 错误。

Rahul Jograna 的答案是正确的。

请参阅此链接以了解 react-native 组件生命周期。 https://reactjs.org/docs/react-component.html

Rajan
2019-11-12