How to connect react component in react navigation? - javascript

I have created modal in react native. I have added filter option icon in top right corner now when the user clicks on it should open the modal. How can I do that ? I have added Options icon in navigation.js but now how to connect it with modal component ?
In code below setModalVisible is available in filteroptions.js and not in navigation.js
Code:
navigation.js:
Updates: {
screen: UpdatesScreen,
navigationOptions: ({ navigation }) => ({
headerTitle: 'Myapp',
headerRight:<TouchableOpacity onPress={() => {this.setModalVisible(true);}}>
<MenuIcon style={{paddingLeft: 10, paddingRight: 15}} name="md-options" size={25} color="white"/>
</TouchableOpacity>,
})
},
filteroptions.js:
import React, {Component} from 'react';
import {Modal, Text, TouchableHighlight, View, Alert} from 'react-native';
export default class FilteroptionsModel extends Component {
state = {
modalVisible: false,
};
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
render() {
return (
<View style={{marginTop: 22}}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{marginTop: 22}}>
<View>
<TouchableHighlight
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
</View>
);
}
}
When user clicks on filter button in top right corner (see screenshot) he should be able to see the box modal on screen:

Since it is a modal you don't necessarily need to add it to the navigation. You can just include it in your page and initially have it be invisible, then when the user clicks your button you can make the modal visible. But if you want to add it to the navigation why not just add like any other component. However, adding it to the navigation will take you to another page when you navigate to the component. Of course you can add a nested navigator to work around that, but I think it adds unnecessary complexity.
Update
You will first declare a Header component.
export default class MyHeader extends React.PureComponent {
render() {
<View>
<View>...Your left Icon here</View>
<View>...Your Title here</View>
<View>...Your right Icon Here</View>
</View>
}
}
Then in your page you will render this component first, pass as props your handlers and then render the rest of the page.
export default class MyPage extends React.PureComponent {
yourRigthHandler = () => {
this.setState({modaVisible: true});
}
yourLeftHandler = () => {....}
render() {
<View>
<MyHeader
LeftHandler={yourLeftHandler}
LeftHandler={yourRigthHandler}>
....
</MyHeader>
</View>
}
}
inside the handlers you can call the navigation functions to navigate to another page or change the components state to make the moda visible.The handlers will be passed as props to your header and you will add them as onPress handlers to your buttons.

Related

React native useState and return statement not working together

Here whenever i click the icon it doesnt show anything. It supposed to be showing some text and when clicked again it should hide the text. Im using react native.
import React, { useState } from 'react';
import { View, Text, StyleSheet, Button, Image, TouchableOpacity} from 'react-native';
import FontAwesome from 'react-native-vector-icons/FontAwesome';
export default function Edit(props, { navigation }) {
const [slide, setSlide] = useState(false);
const toggle = () => {
setSlide(!slide);
console.log('clicked');
return (
<View>
<Text>random</Text>
<Text>random</Text>
</View>
);
}
return (
<View>
<FontAwesome name="sliders" size={30} color="#000" onPress={() => toggle()}/>
</View>
}
After testing the only thing it shows is the console.log('clicked') message. It does not display anything else. Also the icon displays normally. Everything is working except the and the content in those tags.
Rather than returning the View from your toggle function, you actually need to display that view your view hierarchy (eg what is returned from your component).
I've demonstrated in the example by using a ternary expression -- if slide is true, it gets shown, otherwise it does not.
export default function Edit(props, { navigation }) {
const [slide, setSlide] = useState(false);
const toggle = () => {
setSlide(!slide);
console.log('clicked');
}
return (
<View>
<FontAwesome name="sliders" size={30} color="#000" onPress={() => toggle()}/>
{slide ? <View>
<Text>random</Text>
<Text>random</Text>
</View> : null}
</View>
);
}
Snack example: https://snack.expo.io/7lVezwWs7

Pass state from component to Modal?

I have a component and import it in specific screen, in this screen i have a button when clicks i open modal contain component it's a "recorder" so after i record voices i want to take this voice and save them into Parent screen as a state or something!
in the recorder component, I save voices data into state! but how can i pass it to other parent screens!?
so how can I handle it?
here is shots
Parent Screen "after click add voice I show the modal"
Parent Screen
Here's a modal contain a recorder component
Modal
CODE
Component
" I pass data to PassDataToModal state inside componentDidMount "
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, TouchableOpacity, View} from 'react-native';
import {AudioRecorder, AudioUtils} from 'react-native-audio';
import Sound from 'react-native-sound';
import Icon from 'react-native-vector-icons/MaterialIcons';
class RecorderScreen extends Component {
state = {
PassDataToModal: null,
};
componentDidMount() {
AudioRecorder.requestAuthorization().then(isAuthorised => {
this.setState({hasPermission: isAuthorised});
AudioRecorder.onFinished = data => {
console.log('data', JSON.stringify(data));
this.setState({PassDataToModal: data});
};
});
}
render() {
return (
<View style={styles.container}>
<View style={styles.controls}>
{this._renderPlayButton(() => {
this._play();
})}
{this._renderRecordButton(this.state.recording)}
{this._renderStopButton('Stop', () => {
this._stop().then(() => this.setState({currentTime: 0}));
})}
</View>
<Text style={styles.progressText}>{this.state.currentTime}s</Text>
</View>
);
}
}
export default RecorderScreen;
Parent Screen
import Modal from 'react-native-modal';
import RecorderScreen from './Recorder';
class Order extends Component {
constructor(props) {
super(props);
this.state = {
isModalVisible: false,
};
}
toggleModal = () => {
this.setState({isModalVisible: !this.state.isModalVisible});
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity
onPress={this.toggleModal}
>
<Icon name="mic" color="#333" size={20} />
<Text style={{paddingHorizontal: 5}}>Add Voice</Text>
</TouchableOpacity>
<Modal
style={{margin: 0}}
isVisible={this.state.isModalVisible}
>
<View>
<TouchableOpacity onPress={this.toggleModal}>
<Icon name="close" color="#000" size={25} />
</TouchableOpacity>
<RecorderScreen /> // Component
</View>
</View>
)
}
}
In your parent component pass a function to your RecorderScreen component that will send the necessary data up. Docs on lifting state up.
So in your parent you'd have something like:
setData = (data) => {
// Set this to whatever you need it to be named
this.setState({childData: data});
}
Then pass the function as a prop:
<RecorderScreen setData={this.setData} />
And finally, call it in the child however needed (If I'm following the code something like this):
componentDidMount() {
AudioRecorder.requestAuthorization().then(isAuthorised => {
this.setState({hasPermission: isAuthorised});
AudioRecorder.onFinished = data => {
this.props.setData(data);
};
});
}
Then your parent component will have access to the child's data that you have lifted up.

How can I detect which <View> my finger is currently on?

I have a structure like this:
<View style={container}>
<View style={first}></View>
<View style={second}><View>
<View style={third}</View>
</View>
The container pretty much fills the whole screen.
When the user touches the container and moves the finger around without lifting the finger, I would like to know which View the finger is currently placed at.
Use TouchableWithoutFeedback to wrap around your views, and then you can call the onPressIn function to detect touch event.
You cannot detect the touched view unless and until you don't have any touch event on it.
To do that you can use TouchableOpacity (respond to the press and have visual feedback when touched.) or TouchableWithoutFeedback (it won't show any visual feedback when touched)
Below is the sample example as required:
import React, { Component } from 'react'
import {
TouchableOpacity,
View
} from 'react-native'
export default class SampleComponent extends Component {
constructor(props) {
super(props)
}
_onPressView = (viewName) => {
console.log("Tapped View ===> ", viewName)
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => this._onPressView("FirstView")}>
<View style={styles.first}/>
</TouchableOpacity>
<TouchableOpacity onPress={() => this._onPressView("SecondView")}>
<View style={styles.second}/>
</TouchableOpacity>
<TouchableOpacity onPress={() => this._onPressView("ThirdView")}>
<View style={styles.third}/>
</TouchableOpacity>
</View>
);
}
}

How to use custom alert in React Native?

I've created a custom alert as a component in React Native. I used Modal to create this custom alert. My problem is, how to use it? Instead of using Alert.alert in React Native, I want to display my own alert.
Here is my Custom Alert Modal.
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import Modal from 'react-native-modal';
import styles from './style';
import Button from '../../components/Button';
export default class CustomAlert extends Component {
renderModalContent = () => (
<View style={styles.content}>
<Text style={styles.contentTitle}>{this.props.title}</Text>
<Text style={styles.contentInfo}>{this.props.content}</Text>
<View style={styles.buttonContainer}>
<Button
color={this.props.buttonColor}
text={this.props.buttonText}
onPress={this.props.buttonOnPress}
/>
</View>
</View>
);
render() {
return (
<View style={styles.container}>
<Modal
isVisible={this.props.isVisible}
backdropColor="#000000"
backdropOpacity={0.9}
animationIn="zoomInDown"
animationOut="zoomOutUp"
animationInTiming={600}
animationOutTiming={600}
backdropTransitionInTiming={600}
backdropTransitionOutTiming={600}
>
{this.renderModalContent()}
</Modal>
</View>
);
}
}
This is how I want to use it. I want to display this alert through a function. That means when function catches up with an error, I want to show my custom alert.
myFunction()
.then(() => // do something)
.catch(() => // show my custom alert);
Can you help me please to solve this problem?
set isVisible true in your catch block.
myFunction()
.then(() => // do something)
.catch((e) => this.setState({ isVisible: true }))

Getting 'undefined is not an object' when calling navigation prop methods in react native navigation

I'm having trouble calling react navigation methods from custom components outside of my original screens, specifically the one I'm working on right now is trying to call goBack() in a back arrow of a custom header component I made (code below). The error message I'm getting when I click the back arrow is:
undefined is not an object (evaluating '_this2.props.navigation.goBack')
Here is the code:
// HeaderText.js
import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Platform } from 'react-native';
import { Icon } from 'expo';
export class HeaderText extends React.Component {
render() {
const needsBackButton = this.props.backIcon;
if (needsBackButton) {
return(
<View style={[styles.headerStyle,styles.buttonHeaderStyle]}>
<TouchableOpacity onPress={() => this.props.navigation.goBack()} style={styles.backButtonStyles}><Icon.Ionicons size={25} style={{ color: '#fff', fontWeight: 'bold' }} name={Platform.OS === 'ios' ? `ios-arrow-back` : 'md-arrow-back'} /></TouchableOpacity>
<Text style={styles.textStyle}>{this.props.headerText}</Text>
<View style={styles.emptyViewStyles} />
</View>
);
} else {
return(
<View style={styles.headerStyle}>
<Text style={styles.textStyle}>{this.props.headerText}</Text>
</View>
);
}
}
}
Here is the screen I'm putting that HeaderText component in:
// SubmitReferralScreen.js
import React from 'react';
import {
Image,
Platform,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
ImageBackground
} from 'react-native';
import { MonoText } from '../../components/general/StyledText';
import { HeaderText } from '../../components/general/HeaderText';
import { HomeScreenContainer } from '../../components/homeScreen/HomeScreenContainer';
import { IconButton } from '../../components/general/IconButton';
import { StatusInfo } from '../../constants/StatusInfo';
import SvgUri from 'react-native-svg-uri';
export default class SubmitReferralScreen extends React.Component {
static navigationOptions = {
header: null,
};
render() {
return (
<View style={{flex: 1, width: '100%',justifyContent: 'center', alignItems: 'center'}}>
<ImageBackground source={require('../../assets/images/background.png')} style={{width: '100%', height: '100%', flex: 1, justifyContent: 'flex-start', alignItems: 'center', backgroundColor: 'background-color: rgba(0, 0, 0, 0.5)',}}>
<HeaderText backIcon='true' headerText='New Referral' />
<Text>Submit referral here!</Text>
</ImageBackground>
</View>
);
}
}
And here is my Stack Navigator for the referral Screens:
// MainTabNavigator.js
const ReferralStack = createStackNavigator({
Referrals: ReferralScreen,
MakeReferral: SubmitReferralScreen,
});
I've looked at this StackOverflow answer: Getting undefined is not an object evaluating _this.props.navigation
And the answer there was to put only navigation.navigate(YourScreen). I tried that, and the error I got said "cannot find variable navigation".
How can I call navigation props from custom react native components?
By default only screen components are provided with the navigation prop. You can either use library provided ways of hooking up arbitrary components to the navigation state, or you can pass navigation as a prop manually.
Option #1. Using withNavigation:
React navigation exports a higher-order component through which you can inject the navigation props into any component you want. To do this, you can do something like:
Don't immediately export the HeaderText component class (remove export from that line)
At the bottom of that file add export default withNavigation( HeaderText );
or if you don't want to use a default export and keep it as a named export, instead do:
const NavigationConnected = withNavigation( HeaderText );
export { NavigationConnected as HeaderText };
Option #2. Passing navigation as prop: In your SubmitReferralScreen component you can simply pass this.props.navigation as a prop to the HeaderText component like: <HeaderText navigation={ this.props.navigation } />
It's because your navigation prop didn't found where is the navigation's value prop from the parent. Better you make HeaderText component using regular arrow function, like this;
const HeaderText = ({ needsBackButton }) => {
if(needsBackButton) {
return (
<View style={[styles.headerStyle,styles.buttonHeaderStyle]}>
<TouchableOpacity onPress={() => this.props.navigation.goBack()} style={styles.backButtonStyles}><Icon.Ionicons size={25} style={{ color: '#fff', fontWeight: 'bold' }} name={Platform.OS === 'ios' ? `ios-arrow-back` : 'md-arrow-back'} /></TouchableOpacity>
<Text style={styles.textStyle}>{this.props.headerText}</Text>
<View style={styles.emptyViewStyles} />
</View>
)
}
return (
// another component
)
}
And then, You can simply use useNavigation() to access navigation prop from any screen/component.
First, import useNavigation on component that handled function of the moving screen.
import { useNavigation } from '#react-navigation/native';
Create some constant to reference this module:
const navigation = useNavigation()
And then, simply use this on your TouchableOpacity's onPress prop like this;
<TouchableOpacity
onPress={() => navigation.goBack()}
style={styles.backButtonStyles}
>
//...
</ TouchableOpacity>
Get the complete documentation on this:
https://reactnavigation.org/docs/connecting-navigation-prop/

Categories