如何在选项卡导航器的屏幕之间传递数据,当在第一个屏幕中按下按钮而不被路由到第二个屏幕时?

How to pass data between the screens of a tab navigator, when pressing a button in the 1st screen and WITHOUT being routed to the 2nd screen?

我有一个带有 2 个屏幕的底部选项卡导航器:Screen1 和 Screen2。

在 Screen1 中,有一个 FlatList 显示“水果”列表的内容: 它由一个项目和旁边的“添加”按钮组成。 当按下按钮时,该项目将显示在 Screen2 中。

我想在按下“添加”按钮时将 Screen1 中“水果”列表中的项目传递到 Screen2,而不自动路由到 Screen2。

到目前为止,我可以使用以下方法将项目从 Screen1 传递到 Screen2:navigation.navigate("Screen2", {item}),但它会自动将我带到 Screen2,这不是我想要的。

我觉得navigationprop的dispatch方法可以解决这个问题,但是不知道怎么用!

我正在使用 React Native 0.65 和 React Navigation 6.x。

调度方法的官方文档如下: https://reactnavigation.org/docs/navigation-prop/#dispatch

提前致谢。

这是我的代码:

import React from 'react';
import { Text, View, FlatList, Button, StyleSheet } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Constants from 'expo-constants';

const fruits = [
  'apples',
  'watermelons',
  'tomatoes',
  'pomegranates',
  'strawberries'
];

function Screen1({ navigation }) {
  const renderItems = ({ item }) => {
    return (
      <View style={styles.item_container}>
        <Text style={styles.text}>{item}</Text>
        <Button 
          title="add"
          onPress={() => navigation.navigate('Screen2', { item })}
        />
      </View>
    );
  };
  return (
    <View style={styles.container}>
      <FlatList
        data={fruits}
        renderItem={renderItems}
        keyExtractor={(item) => item}
      />
    </View>
  );
}

function Screen2({ route }) {
  const { item } = route.params;
  return (
    <View style={styles.container}>
      <Text  style={styles.text}>{item}</Text>
    </View>
  );
}

const Tab = createBottomTabNavigator();

export default function TabNavigator() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen
          name="Screen1"
          component={Screen1}
           options={{
            tabBarLabel: 'Screen 1',
           }}
        />
        <Tab.Screen
          name="Screen2"
          component={Screen2}
          options={{
            tabBarLabel: 'Screen 2',
          }}
        />
     </Tab.Navigator>
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    paddingTop: Constants.statusBarHeight,
  },
  item_container: {
    flexDirection: 'row',
    margin: 5,
  },
  text: {
    fontSize: 20,
    margin: 5
  }
});

不幸的是,由于您使用的是 React Native,它使用底层的本机 API 而您没有使用 Web 视图,因此您只能执行本机 iOS & Android 行为是。

在 Android 中,活动标签旁边的 2 个非活动标签(左侧和右侧)会在该活动标签打开时立即呈现。因此,当您点击下一个选项卡时,它实际上不需要做任何其他工作,从而可以快速加载。

因此您必须利用 state 管理库。每当有状态 属性 更新时,它都会强制重新呈现使用它的页面。因此,如果您在一个选项卡中分配一个新值,它应该会使用新值自动刷新任何相邻页面中的 UI。

谢谢大家的回答!事实上,Redux 是解决方案,我能够实现代码。

这是解决方案:)

import Constants from 'expo-constants';
import React, { useEffect } from 'react';
import { Text, View, FlatList, Button, StyleSheet } from 'react-native';
import { Provider, connect } from 'react-redux';
import { createStore, combineReducers } from 'redux';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer } from '@react-navigation/native';

const fruits = ['apples', 'watermelons', 'tomatoes', 'pomegranates',  'strawberries'];

function reducer(state, action) {
  if (typeof state === 'undefined') {
    return 'nothing!';
  }
  if (action.type === 'addItem') {
    return action.value.item;
  }
  return state;
}

const store = createStore(combineReducers({ selectedItem: reducer }));

function Screen1({ selectedItem }) {
  useEffect(() => {
    console.log(store.getState());
  }, [selectedItem]);

  const renderItems = ({ item }) => {
    return (
      <View style={styles.item_container}>
        <Text style={styles.text}>{item}</Text>
        <Button
          title="add"
          onPress={() =>
            store.dispatch({
              type: 'addItem',
              value: { item }
            })
          }
        />
      </View>
    );
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>My favorite fruits:</Text>
      <FlatList
        data={fruits}
        renderItem={renderItems}
        keyExtractor={(item) => item}
      />
    </View>
  );
}

function Screen2({ selectedItem }) {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>You selected {selectedItem}</Text>
    </View>
  );
}

// Connect the screens to Redux
const Screen1Container = connect((state) => ({
  selectedItem: state.selectedItem,
}))(Screen1);
const Screen2Container = connect((state) => ({
  selectedItem: state.selectedItem,
}))(Screen2);

// Create the stack navigator
const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <Provider store={store}>
      <NavigationContainer>
        <Tab.Navigator>
          <Tab.Screen
            name="Screen1"
            component={Screen1Container}
            options={{
              tabBarLabel: 'Screen 1',
            }}
          />
          <Tab.Screen
            name="Screen2"
            component={Screen2Container}
            options={{
              tabBarLabel: 'Screen 2',
            }}
          />
        </Tab.Navigator>
      </NavigationContainer>
    </Provider>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    //justifyContent: 'center',
    alignItems: 'center',
    paddingTop: Constants.statusBarHeight,
  },
  title: {
    fontSize: 25,
  },
  item_container: {
    flexDirection: 'row',
    marginVertical: 7,
  },
  text: {
    fontSize: 20,
    marginHorizontal: 7,
  },
});