React Native/Shoutem: navigateBack() not working - react-native

My Problem is that I would like to navigateBack() from the BountyDetailsScreen to the LoyaltyScreen, but the navigateBack() function call does not trigger any action. When I log the function it says:
The only thing I notice is, that the navigationStack is empty. When I do the same with the navigateTo function it is working, but then I have a messed up navigation stack.
In my LoyaltyScreen.js I am displaying a ListView. It is a RN ListView (not imported from shoutem).
LoyaltyScreen.js
renderRow(bounty) {
return (
<ListBountiesView
key={bounty.id}
bounty={bounty}
onDetailPress={this.openDetailsScreen}
redeemBounty={this.redeemBounty}
/>
);
}
ListBountiesView.js
The ListBountiesView renders each ListView Row and opens a Detail Screen when clicked on the Row.
render() {
const { bounty } = this.props;
return (
<TouchableOpacity onPress={this.onDetailPress}>
{bounty.type == 0 ? this.renderInShopBounty() : this.renderContestBounty()}
<Divider styleName="line" />
</TouchableOpacity>
);
}
BountyDetailsScreen.js
In the BountyDetailsScreen I display detailed information and would like to navigateBack() to the Loyalty Screen when I press a button.
<Button styleName="full-width" onPress={() => this.onRedeemClick()}>
<Icon name="add-to-cart" />
<Text>Einlösen</Text>
</Button>
onRedeemClick() {
const { bounty, onRedeemPress } = this.props;
onRedeemPress(bounty);
navigateBack();
}

navigateBack is an action creator. You need to map it to props and read it from props in your redeemClick function. Just executing the imported action creator won't do anything since it's not connected to Redux.
Here's an example of you map it to props:
export default connect(mapStateToProps, { navigateBack })(SomeScreen));
Here's how you use it:
const { navigateBack } = this.props;
navigateBack();

I can see that airmiha's answer is what you're looking for, but I just wanted to add onto it.
You can also use hasHistory to set up your #shoutem/ui NavigationBar (if you're using it) with a simple back button that utilises navigateBack().
<NavigationBar
styleName="no-border"
hasHistory
title="The Orange Tabbies"
share={{
link: 'http://the-orange-tabbies.org',
text: 'I was underwhelmed by The Orange Tabbies, but then I looked at that
sweet, sweet back button on the Nav Bar.
#MakeNavBarsGreatAgain',
title: 'Nevermind the cats, check the Nav Bar!',
}}
/>
You can find more examples with the NavigationBar component here.

Related

React - native StackNavigator refresh previous component after hitting back button

I'm stuck for weeks on this problem that I can't solve. I have been through a lot of different solution and none of them is working..
Let-s say I have component A and component B
Component A : contains a flatlist, when click on one item leads me to component B.
Component B: contains details of component A items, when clicking on a button update data, data that component A is using in state current, which make the clicked items turn to orange. I would like when hitting back button to update those data in component A and actually have the clicked items in orange, right now nothing is happening..
Component A :
async interventionList(){
const planningList = await getInterventionList(this.state.userToken, '2019-02-27', '2019-02-27');
this.setState({list: planningList});
}
renderItem = ({ item }) => (
<View>
<TouchableHighlight onPress={
() => this.props.navigation.navigate('InterventionStart', { getIntervention: () => this.interventionsList() })}>
<View style={[styles.block, this.state.current !== null && this.state.current.remoteInterventionId === item.num ? styles.began : styles.notbegan]}>
<Text> {SomeData} <Text>
</View>
</View>
</TouchableHighlight>
</View>
)
Component B :
componentWillUnmount() {
this.props.navigation.state.params.getIntervention();
}
But nothing happens. I tried to console log, to see if those functions where called after clickin on back button and they are... So I don't understand what I am doing wrong or is it not the way to do this at all ?
You can use willFocus method of react-navigation
in your componentDidMount or in your constructor
this.willFocus = this.props.navigation.addListener('willFocus', () => {
this.interventionList();
});
It will call your interventionList method whenever your component is about to be focused. Make sure you remove the listener on your componentWillUnmount
this.willFocus.remove();
For reference
https://reactnavigation.org/docs/en/navigation-events.html

Opening context menu on long press in React Native

I'd like to have a context menu triggered on long press different places using React Native.
I.e. in a dialer like the default dailer. You can long-click on any contact and get a 'copy number' menu. And also you can long-click on the name of the person once you've opened their 'contact card'.
The straight-forward way needs a lot of copy-pasted boilerplate, both components and handlers.
Is there a better pattern for doing this?
All Touchable components (TouchableWithoutFeedback, TouchableOpacity etc.) has a property called onLongPress. You can use this prop to listen for long presses and then show the context menu.
To eliminate code mess and doing lots of copy paste you can separate your context menu as a different component and call it when the long press happen. You can also use an ActionSheet library to show the desired options. React native has a native API for iOS called ActionSheetIOS. If you get a little bit more experience in react and react-native you can create a better logic for this but I'm going to try to give you an example below.
// file/that/contains/globally/used/functions.js
const openContextMenu = (event, user, callback) => {
ActionSheetIOS.showActionSheetWithOptions({
options: ['Copy Username', 'Call User', 'Add to favorites', 'Cancel'],
cancelButtonIndex: [3],
title: 'Hey',
message : 'What do you want to do now?'
}, (buttonIndexThatSelected) => {
// Do something with result
if(callback && typeof callback === 'function') callback();
});
};
export openContextMenu;
import { openContextMenu } from './file/that/contains/globally/used/functions';
export default class UserCard extends React.Component {
render() {
const { userObject } = this.props;
return(
<TouchableWithoutFeedback onLongPress={(event) => openContextMenu(event, userObject, () => console.log('Done')}>
<TouchableWithoutFeedback onLongPress={(event) => openContextMenu(event, userObject, () => console.log('Done'))}>
<Text>{userObject.name}</Text>
<Image source={{uri: userObject.profilePic }} />
</TouchableWithoutFeedback>
</TouchableWithoutFeedback>
);
}
}
Similarly as the previous answer combine onLongPress with imperative control for popup menu - something like
<TouchableWithoutFeedback onLongPress={()=>this.menu.open()}>
<View style={styles.card}>
<Text>My first contact name</Text>
<Menu ref={c => (this.menu = c)}>
<MenuTrigger text="..." />
<MenuOptions>
// ...
</MenuOptions>
</Menu>
</View>
</TouchableWithoutFeedback>
When it comes to a lot of boilerplate - in React you can do your own components that you can reuse everywhere thus reducing boilerplate (and copy&paste)
See full example on https://snack.expo.io/rJ5LBM-TZ

How to show a List item after click button in react native

I'm a new to react-native and i need a help. I want to do this: I have a button, when click it, a list item will show under the button. Help me guys !
Thanks
I suggest you to use or learn (if you want make your own popover) from react-native-list-popover. Here some screenshot from reace-native-list-popover:
Make a Boolean flag in your component state and initiate it with false and then use it for showing the list. You can use FlatList for make a good list.
The example code can be like this:
export default class ClassName extends Component {
state = {showList: false}
_onPress = () => {
this.setState({showList: true})
}
render() {
return (
<View>
<Button onPress={this._onPress}>Show List</Button>
{(this.state.showList) && <FlatList
data={[{key: 'a'}, {key: 'b'}]}
renderItem={({item}) => <Text>{item.key}</Text>}
/>}
</View>
)
}
}

Changing Drawer left and right button image dynamically?

react-native-router-flux v3.37.0
react-native v0.42.0
I'm trying to update drawer navigation bar right image dynamically where I have used leftButtonImage, rightButtonImage, where once user read all the notification I want to change the button image.
I could not manage to re-render or update this button image, Is this feature not supported or is there something that I'm missing?
You can call Actions.refresh when you need to refresh the view, example:
Actions.refresh({key: 'profileView', renderRightButton: this.renderRightButton });
and also define renderRightButton:
renderRightButton() {
return (
<TouchableOpacity onPress={ console.log(this) } >
<Text>Logout</Text>
</TouchableOpacity>
)
}
and lastly don't forget to import Actions from react-native-router-flux
import {Actions} from 'react-native-router-flux';
You can re-render using props or states naturally.
Check the states you want, and apply image resource following the states.(or props)
let NotiImage = {
normal: require('../assets/image/notinormal.png');
new: require('../assets/image/new.png');
}
render() {
...
<Image source={ this.state.newNoti ? NotiImage.new : NotiImage.normal } />
...
}

React Native Navigator: Can I remove navigation gestures from a scene after a user action?

I want to disable the swipe from left pop gesture on the navigator after the side menu has been accessed within a scene. I don't want to disable it when the scene first renders, only when the side menu is open. I have an onOpen function I can call, but I don't know how to programatically change the navigation gestures without pushing another route.
I tried setting the configureScene prop of the navigator like this:
configureScene={() => {
return this.state.swipeBackNavigation ? FloatFromRight : Navigator.SceneConfigs.FloatFromRight;
}
and changing the state, but the component doesn't rerender
ideas would be appreciated
I believe you can just set gestures to null (effectively disabling it):
gestures: {}
I can't test this currently, but I suspect it will work (if I didn't screw up some syntax somewhere):
export default class Foo extends Component {
constructor(props){
super(props);
this.state = {
//initialize gestureChoice
gestureChoice: {},
}
}
disablePop(){
setState({ gestureChoice:{ gestures:{} } });
}
enablePop(){
setState({gestureChoice: ...Navigator.SceneConfigs.FloatFromRight});
}
render(){
return(
<Navigator
renderScene={(route, navigator) =>
return <SomeScene navigator={navigator} {...route.passprops} />
}
configureScene={(route, routeStack) =>
this.state.gestureChoice;
)}
/>
);
}
}
The idea being, you could use enablePop() and disablePop() whenever you would like.
This thread is probably helpful: https://github.com/facebook/react-native/issues/1014