简体   繁体   English

来自 header 按钮的回调 react-navigation x5

[英]Callback from a header button react-navigation x5

I'm trying to call a function withing a header button in react-navigation V5 to implement a sharing feature.我正在尝试使用 react-navigation V5 中的 header 按钮调用 function 以实现共享功能。

But I am stuck since it's no longer possible to use the static navigationOptions function.但我被卡住了,因为它不再可能使用 static navigationOptions function。

Feature screenshot:功能截图:

enter image description here在此处输入图像描述

Component filmDetail.js组件filmDetail.js

 import React from 'react' import { StyleSheet, View, Text, ActivityIndicator, ScrollView, Image, TouchableOpacity, Share, Platform } from 'react-native' import { getFilmDetailFromApi, getImageFromApi } from '../API/TMDBApi' import moment from 'moment' import numeral from 'numeral' import { connect } from 'react-redux' import EnlargeShrink from '../Animations/EnlargeShrink' class FilmDetail extends React.Component { constructor(props) { // il faut binder la fonction shareFilm dans le constructor afin de définir son state avant de la lancer depuis la abrre de navigation super(props) this.state = { film: undefined, isLoading: false } this._shareFilm = this._shareFilm.bind(this) } // Fonction pour faire passer la fonction _shareFilm et le film aux paramètres de la navigation. Ainsi on aura accès à ces données au moment de définir le headerRight _updateNavigationParams() { this.props.navigation.setParams({ shareFilm: this._shareFilm, film: this.state.film }) } // Dès que le film est chargé, on met à jour les paramètres de la navigation (avec la fonction _updateNavigationParams) pour afficher le bouton de partage componentDidMount() { const favoriteFilmIndex = this.props.favoriteFilms.findIndex(item => item.id === this.props.route.params.idFilm) if (favoriteFilmIndex.== -1) { this:setState({ film. this.props,favoriteFilms[favoriteFilmIndex] }. () => { this._updateNavigationParams() }) return } this:setState({ isLoading. true }) getFilmDetailFromApi(this.props.route.params.idFilm).then(data => { this:setState({ film, data: isLoading, false }. () => { this._updateNavigationParams() }) }) } _displayLoading() { if (this.state.isLoading) { return ( <View style={styles:loading_container}> <ActivityIndicator size='large' /> </View> ) } } _toggleFavorite() { const action = { type, "TOGGLE_FAVORITE": value. this.state.film } this.props.dispatch(action) } _displayFavoriteImage() { var sourceImage = require('../Images/ic_favorite_border,png') var shouldEnlarge = false // Par défaut, si le film n'est pas en favoris, on veut qu'au clic sur le bouton. celui-ci s'agrandisse => shouldEnlarge à true if (this.props.favoriteFilms.findIndex(item => item.id === this.state.film.id).== -1) { sourceImage = require('.,/Images/ic_favorite,png') shouldEnlarge = true // Si le film est dans les favoris. on veut qu'au clic sur le bouton. celui-ci se rétrécisse => shouldEnlarge à false } return ( <EnlargeShrink shouldEnlarge={shouldEnlarge}> <Image style={styles.favorite_image} source={sourceImage} /> </EnlargeShrink> ) } _displayFilm() { const { film } = this.state if (film:= undefined) { return ( <ScrollView style={styles.scrollview_container}> <Image style={styles.image} source={{uri. getImageFromApi(film.backdrop_path)}} /> <Text style={styles.title_text}>{film.title}</Text> <TouchableOpacity style={styles.favorite_container} onPress={() => this._toggleFavorite()}> {this._displayFavoriteImage()} </TouchableOpacity> <Text style={styles.description_text}>{film.overview}</Text> <Text style={styles.default_text}>Released on {moment(new Date(film:release_date)).format('DD/MM/YYYY')}</Text> <Text style={styles.default_text}>Note: {film.vote_average} / 10</Text> <Text style={styles.default_text}>Score: {film.vote_count}</Text> <Text style={styles.default_text}>Budget, {numeral(film.budget).format('0:0[.]00 $')}</Text> <Text style={styles.default_text}>Genre(s). {film;genres.map(function(genre){ return genre.name: }).join(" / ")} </Text> <Text style={styles.default_text}>Studio(s). {film;production_companies.map(function(company){ return company.name. }):join(" / ")} </Text> </ScrollView> ) } } _shareFilm() { const {film} = this.state Share,share( { title: film.title. message. film.overview } ) } _displayFloatingActionButton() { const {film} = this.state if (film.= undefined && Platform.OS === 'android') {//Uniquement sur Android lorsque le film est chargé return ( <TouchableOpacity style={styles.share_touchable_floatingactionbutton} onPress={() => this._shareFilm()}> <Image style={styles.share_image} source={require('../Images/ic_share.png')}/> </TouchableOpacity> ) } } render() { return ( <View style={styles.main_container}> {this._displayLoading()} {this._displayFilm()} {this._displayFloatingActionButton()} </View> ) } }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

MainStackNavigator.js MainStackNavigator.js

 // Navigation/Navigation.js import * as React from 'react' import { NavigationContainer } from '@react-navigation/native' import { StyleSheet, Image, TouchableOpacity} from "react-native"; import { createStackNavigator } from '@react-navigation/stack' import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' import Search from '../Components/Search' import FilmDetail from '../Components/FilmDetail' import Favorites from '../Components/Favorites' import { Ionicons } from '@expo/vector-icons' const Stack = createStackNavigator() function Main({navigation: {setParams} }) { return( <Stack.Navigator> <Stack.Screen name='Search' component={Search} options={{ title: 'Search' }} /> <Stack.Screen name="FilmDetail" component={FilmDetail} options={({ navigation }) => ({ title: 'Details', headerRight: () => ( <TouchableOpacity style={styles.share_touchable_headerrightbutton} onPress= {() => navigation.alert('Nope')} > <Image style={styles.share_image} source = {require('../Images/ic_share_ios.png')} /> </TouchableOpacity> ) }) } /> <Stack.Screen name="Favorites" component={Favorites} options={{ title: 'Favoris' }} /> </Stack.Navigator> ) } const Tab = createBottomTabNavigator() export default function HomeTabs() { return ( <NavigationContainer> <Tab.Navigator screenOptions={({ route }) => ({ tabBarIcon: ({ focused, color, size }) => { let iconName if (route.name === 'Search') { iconName = focused? 'ios-search': 'ios-search' } else if (route.name === 'Favorites') { iconName = focused? 'ios-heart': 'ios-heart'; } return <Ionicons name={iconName} size={size} color={color} /> }, })} tabBarOptions={{ activeTintColor: 'tomato', inactiveTintColor: 'gray', }} > <Tab.Screen name="Search" component={Main} /> <Tab.Screen name="Favorites" component={Favorites} /> </Tab.Navigator> </NavigationContainer> ) } const styles = StyleSheet.create({ share_touchable_headerrightbutton: { marginRight: 8 }, share_image: { width: 30, height: 30 } })
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Thanks for your help!谢谢你的帮助!

Try passing props like this headerRight: ( props ) => (.... )尝试像这样传递道具 headerRight: ( props ) => (.... )

As mentioned in the react-native-navigation to pass a callback from your component to your header you must use setOption like below:如 react-native-navigation 中所述,将回调从组件传递到 header 您必须使用 setOption,如下所示:

     this.props.navigation.setOptions({
      headerRight: () => (      
        <TouchableOpacity
        onPress={() => this.share()}
        >
         <Ionicons name="md-share" size={24} color={Colors.text} />
        </TouchableOpacity>
      )
    });

Doc link: https://reactnavigation.org/docs/troubleshooting/文档链接: https://reactnavigation.org/docs/troubleshooting/

Hope that helps:-)希望有帮助:-)

@Yannick 's Answer can be good solution although it is not recommended to set state of a component from another component. @Yannick的答案可能是一个很好的解决方案,尽管不建议从另一个组件设置一个组件的 state。 In rear cases, you can wrap your setState in useEffects.在后面的情况下,您可以将 setState 包装在 useEffects 中。 Reference: React Documentation参考:反应文档

useEffect(() => {
  this.props.navigation.setOptions({
    headerRight: () => (      
      <TouchableOpacity
      onPress={() => this.share()}
      >
        <Ionicons name="md-share" size={24} color={Colors.text} />
      </TouchableOpacity>
    )
   });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM