如何在 React Native 中重新加载视图点击 TabNavigator

How To Reload View Tap on TabNavigator in React Native

我想在用户每次更改选项卡时重新加载 tabNavigator。当用户更改选项卡时,不会调用 React Native 的生命周期方法。那么如何才能在 TabNavigator 中重新加载选项卡:

下面的示例有两个选项卡:1) 主页 2) 事件。现在我想在主页选项卡中的用户 returns 时刷新事件选项卡。

世博会 LINK : Expo Tab Navigator

代码:

import React, {Component} from 'react';
import  {View, StyleSheet, Image, FlatList, ScrollView, Dimensions } from 'react-native';
import { Button, List, ListItem, Card  } from 'react-native-elements' // 0.15.0
//import { Constants } from 'expo';
import { TabNavigator, StackNavigator } from 'react-navigation'; // 1.0.0-beta.11

//image screen width and height defs
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;


export default class App extends Component {
  render() {
    //const { navigate } = this.props.navigation;
    return (
      <TabsNav  />
      )
  }
  }


class MyHomeScreen extends Component {
  render() {
    return (
      <View>
            <Image
              resizeMode="cover"
              style={{    width: windowWidth * .85,    height: windowHeight * 0.3}}
              source={{uri: 'http://www.ajaxlibrary.ca/sites/default/files/media/logo.png?s358127d1501607090'}}
            />
            <Button
              onPress={() => this.props.navigation.navigate('Notifications')}
              title="Go to notifications"
            />
      </View>

    );
  }
}

class AplEvents extends Component {
  static navigationOptions = {
    tabBarLabel: 'Events List',
    tabBarIcon: ({ tintColor }) => (
      <Image
        source={{uri: 'https://facebook.github.io/react/img/logo_og.png'}}
        style={[styles.icon, {tintColor: tintColor}]}
      />
    ),
  };

    constructor(props) {
    super(props);

    this.state = {
      data: [],
      error: null,
    };
  }

  // when component mounts run the function fetch
  componentDidMount() {
    this.makeRemoteRequest();
  }

  makeRemoteRequest = () => {
    const url = `http://www.ajaxlibrary.ca/?q=calendar-test`;

    fetch(url)
      .then((res) => res.json())
      .then((res) => {
        this.setState({
          data: [...this.state.data, ...res.nodes],
          error: res.error || null,
        });
      })
      .catch(error => {
        this.setState( error );
      });
  };


  render() {
    const { navigate } = this.props.navigation;
    return (
         <List containerStyle={{ marginTop: 0, borderTopWidth: 0, borderBottomWidth: 0 }}>
        <FlatList
          data={this.state.data}
          renderItem={({ item }) => (
            <ListItem
              //squareAvatar
              title={`${item.node.title}\n${item.node.Program_Location}`}
              subtitle={item.node.Next_Session}
              avatar={{ uri: item.node.Image }}
              containerStyle={{ borderBottomWidth: 0 }}
             // save params to pass to detailed events screen
              onPress={() => navigate('Details', {title: `${item.node.title}`,
                                                body: `${item.node.Body}`,
                                                date: `${item.node.Date}`,
                                                Next_Session: `${item.node.Next_Session}`,
                                                Program_Location: `${item.node.Program_Location}`,
                                                Nid: `${item.node.Nid}`,
                                                Image: `${item.node.Image}`,
                                                Run_Time: `${item.node.Run_Time}`})}
            />
          )}
          keyExtractor={item => item.node.Nid}
        />
        </List>
    );
  }
}

class EventDetails extends Component {
      static navigationOptions = {
    title: 'EventDetails'
  };
  render() {
    const { params } = this.props.navigation.state;

    let pic = {
      uri: `${params.Image}`
    };
    //const pic = { params.Image };
    return (

          <ScrollView>

              <Card
                title={params.title}
              >
                  <Image
                      resizeMode="cover"
                       style={{    width: windowWidth * .85,    height: windowHeight * 0.3}}
                      source={pic}
                  />

                  <Button style={{marginTop: 10}}
                      icon={{name: 'date-range'}}
                      backgroundColor='#03A9F4'
                      fontFamily='Lato'
                      buttonStyle={{borderRadius: 0, marginLeft: 0, marginRight: 0, marginBottom: 0}}
                      title='Add to Calendar'
                  />
                    <ListItem
                     title="Event Description"
                     subtitle={params.body}
                     hideChevron='true'
                    />
                    <ListItem
                     title="Date"
                     subtitle={`${params.Next_Session}\n Run Time - ${params.Run_Time}`}
                     hideChevron='true'
                    />
                    <ListItem
                     title="Location"
                     subtitle={params.Program_Location}
                     hideChevron='true'
                    />
              </Card>
          </ScrollView>
    );
  }
}


const styles = StyleSheet.create({
  icon: {
    width: 26,
    height: 26,
  },
});

const EventStack = StackNavigator({
    EventList: {
        screen: AplEvents,
          navigationOptions: {
            title: "APL Event Listing",
          }
    },
    Details: {
        screen: EventDetails,
    },
  TabsNav: { screen: MyHomeScreen}
  });

const TabsNav = TabNavigator({
  Home: {
    screen: MyHomeScreen,
        navigationOptions: {
            tabBarLabel: 'Home',
                 tabBarIcon: ({ tintColor }) => (
                <Image
                    source={{uri: 'https://upload.wikimedia.org/wikipedia/de/thumb/9/9f/Twitter_bird_logo_2012.svg/154px-Twitter_bird_logo_2012.svg.png'}}
                    style={[styles.icon, {tintColor: tintColor}]}
                />
                ),
        },
  },
  EventList: {
    screen: EventStack,
            navigationOptions: {
            tabBarLabel: 'Events',
                 tabBarIcon: ({ tintColor }) => (
                <Image
                    source={{uri: 'https://upload.wikimedia.org/wikipedia/de/thumb/9/9f/Twitter_bird_logo_2012.svg/154px-Twitter_bird_logo_2012.svg.png'}}
                    style={[styles.icon, {tintColor: tintColor}]}
                />
                ),
        },
  },
}, {
  tabBarOptions: {
    activeTintColor: '#e91e63',
  },
});

react-native 问题对此进行了很多长时间的讨论 314, 486, 1335, and finally we got a way to handle this, after Sep 27, 2017, react-navigation version v1.0.0-beta.13:

New Features

Accept a tabBarOnPress param (#1335) - @cooperka

我们开始吧,

用法:

const MyTabs = TabNavigator({
  ...
}, {
  tabBarComponent: TabBarBottom /* or TabBarTop */,
  tabBarPosition: 'bottom' /* or 'top' */,
  navigationOptions: ({ navigation }) => ({
    tabBarOnPress: (scene, jumpToIndex) => {
      console.log('onPress:', scene.route);
      jumpToIndex(scene.index);
    },
  }),
});

我无法让它工作,在检查 React Navigation 文档后,发现了这个,这似乎表明更高版本(我使用的是 1.0.0-beta.27)改变了方法单个对象的签名:

tabBarOnPress Callback to handle tap events; the argument is an object containing:

the previousScene: { route, index } which is the scene we are leaving

the scene: { route, index } that was tapped

the jumpToIndex method that can perform the navigation for you

https://reactnavigation.org/docs/en/tab-navigator.html#tabbaronpress

鉴于此,以及来自 beausmith here 的代码,我将其放在一起。

navigationOptions: ({ navigation }) => ({
    tabBarOnPress: (args) => {
        if (args.scene.focused) { // if tab currently focused tab
        if (args.scene.route.index !== 0) { // if not on first screen of the StackNavigator in focused tab.
            navigation.dispatch(NavigationActions.reset({
            index: 0,
            actions: [
                NavigationActions.navigate({ routeName: args.scene.route.routes[0].routeName }) // go to first screen of the StackNavigator
            ]
            }))
        }
        } else {
            args.jumpToIndex(args.scene.index) // go to another tab (the default behavior)
        }
    }
})

请注意,您需要从 react-navigation 导入 NavigationActions 才能正常工作。

希望这对某人有所帮助:)

看看这个link。由于这个,我的问题正在解决。

<Tabs.Navigator
    initialRouteName="Home"
    tabBar={(props) => (
       <TabBar {...props} />
    )}>
    <Tabs.Screen
      name="Home"
      component={HomeView}
      options={{ unmountOnBlur: true }}
      listeners={({ navigation }) => ({
        blur: () => navigation.setParams({ screen: undefined }),
      })}
    />
  </Tabs.Navigator>

https://github.com/react-navigation/react-navigation/issues/6915#issuecomment-692761324

React Native Tab Navigation 有一个选项属性 unmountOnBlur 将其设置为 true 并且它会在您每次单击选项卡时重新加载选项卡屏幕。

<Tab.Screen name={"Profile"} component={ProfileScreen} options={{unmountOnBlur: true}} />

Doc/Ref - RN Bottom tab Navigator docs

.

更新 - '@react-navigation/native' 中有一个名为 useIsFocused 的挂钩。 每次聚焦或使用时,将此与 useEffect 一起使用 re-render 屏幕。

import { useIsFocused } from '@react-navigation/native';

const isFocused = useIsFocused();

useEffect(() => { yourApiCall(); }, [isFocused])