React Native Components Do Not Recognize Taps - javascript

I have just recently switched to React navigation v6 in my RN app and I can't seem to understand why my Button(s) and Touchable(s) do not recognize onPress function the second time they are being pushed.
The scenario:
I launch Home Screen.
Press go to test screen button. The console prints the message.
On Test Screen press go back. The console prints the message. I go back.
Back on the Home Screen the button doesn't work anymore. Console does not print the message
Home.tsx
<View style={{ flex: 1, paddingTop: 30 }}>
<Button
title='go to test screen'
onPress={() => {
console.log('pressed to test');
navigate(TEST_SCREEN);
}}
/>
</View>
TestScreen.tsx
<View style={{flex: 1, paddingTop: 30}}>
<Button
title='go back'
onPress={() => {
console.log('pressed go back');
goBack();
}}
/>
</View>
navigate func:
export function navigate(name: string, params?: any | undefined) {
if (navigationRef.isReady()) {
navigationRef.navigate(name, params);
}
}
navigator:
const Home = createStackNavigator();
export default function HomeNavigator(): JSX.Element {
return (
<Home.Navigator
initialRouteName={HOME_SCREEN}
screenOptions={{ headerShown: false }}
>
<Home.Screen name={HOME_SCREEN} component={HomeScreen} />
<Home.Screen name={TEST_SCREEN} component={TestScreen} />
</Home.Navigator>
);
}
routes:
export const HOME_SCREEN = 'Home';
export const TEST_SCREEN = 'Test';

Related

React native webview crashing on Android

i have screen inside my app where the user is required to enter their 3 digit code to continue. When the user, enters their 3 digit code, a modal with a webview inside is opened. The webview then automatically redirects the user to the correct url where parameters are attached to the url based on my backend and updates a status field inside my database.
On ios, i have used onShouldStartLoadWithRequest to listen to changes inside the url then once the desired url is achieved i Alert the user that it was successful and navigate the user back to the home screen.
On android, since onShouldStartLoadWithRequest doesnt work, i have created an API call to my backend to fetch the value of status every 2 secs and then if status is successful, Alert the user.
On ios, everything is working without any crashes.
On android, 2 crashes occur:
after the webview modal is closed, the textinput field crashes and i am no longer able to enter any input inside (even the placeholder is not visable)
after the webview modal is closed, the alert does not appear
Here is my code:
function Screen({navigation,route}) {
let myWebView;
const [uploadVisible, setUploadVisible] = useState(false);
const[cvv,setCvv]=useState('');
const[authenticateWebView,setAuthenticateWebView]=useState(false);
const handlePayment=async()=>{
setUploadVisible(true);
setUploadVisible(false);
setAuthenticateWebView(true)
}
const[statusUpdated,setStatusUpdated]=useState(false);
const intervalRef = useRef();
const everyTwoSeconds=async()=> {
console.log('android')
const response = await transactionsApi.getTransaction(route.params.transaction.id);
console.log(response)
if(response.data.status==='paid'){
setStatusUpdated(true);
setAuthenticateWebView(false);
{authenticateWebView===false?
Alert.alert('Payment successful',"Your card has been charged",
[
{ text: 'Yes',
onPress:()=> {
navigation.navigate(routes.HOME);
}},
{ text: 'Cancel',style:"cancel" },
]):null}
}
}
const myInterval =()=>{
intervalRef.current=setInterval(()=>{
everyTwoSeconds()
}, 5000);
}
useEffect(() => {
const intervalId = intervalRef.current;
// also clear on component unmount
return () => clearInterval(intervalId);
}, []);
useEffect(() => {
if (statusUpdated===true) {
clearInterval(intervalRef.current);
}
}, [statusUpdated]);
const modal = React.createRef();
const [isKeyboardVisible, setKeyboardVisible] = useState(false);
useEffect(() => {
const keyboardDidShowListener = Keyboard.addListener(
'keyboardDidShow',
() => {
setKeyboardVisible(true); // or some other action
}
);
const keyboardDidHideListener = Keyboard.addListener(
'keyboardDidHide',
() => {
setKeyboardVisible(false); // or some other action
}
);
return () => {
keyboardDidHideListener.remove();
keyboardDidShowListener.remove();
};
}, []);
const keyboardHeight = useKeyboard();
return(
<>
{
authenticateWebView?
<Modal visible={authenticateWebView}>
<View style={{
flex : 1,
justifyContent : 'center',
alignItems : 'center',
backgroundColor: 'rgba(0,0,0,0)'}}>
<View style={{
flex:1,
width:'100%',
flexDirection:'row',
backgroundColor:colorScheme==='dark'?colors.black:colors.white,
justifyContent:'space-between',
alignItems:'center',
paddingTop:Platform.OS='ios'?40:0
}}>
<TouchableOpacity style={{
backgroundColor:colorScheme==='dark'?colors.black:colors.white,
justifyContent:'flex-start',
alignItems:'center',
paddingLeft:20
}}
onPress={()=>{setAuthenticateWebView(false);clearInterval(myInterval)}}
>
<Text style={{color:colors.primary,fontSize:15,fontWeight:'700'}}>
Cancel
</Text>
</TouchableOpacity>
</View>
<View style={{height : '90%',width:'95%',backgroundColor:colors.white}}>
<WebView
style={{flex:1}}
source={{html:`${url}`}}
ref={el=>myWebView=el}
onNavigationStateChange={(navState) => {
console.log(navState)
}}
/>
</View>
</View>
</Modal>
:null
}
<View style={{
flex:1,
backgroundColor:colorScheme==='dark'?colors.dark:colors.white,
paddingBottom:colorScheme==='dark'?0:0,
marginBottom:0,
borderTopRightRadius:10,
borderTopLeftRadius:10,
paddingTop:0,
marginTop:0
}}>
<View
style={{
backgroundColor:colorScheme==='dark'?colors.black:colors.white,
borderRadius:5,
borderWidth:1,
borderColor:colors.primary,
height:30,
marginTop:10,
marginHorizontal:20
}}>
<TextInput
placeholder={"CVV"}
maxLength={3}
keyboardType={"numeric"}
onChangeText={cvv => setCvv(cvv)}
value={cvv.value}
/>
</View>
<AppButton title="Pay now"
onPress={()=>{
console.log(cvv.length)
if(cvv.length!==3){
return Alert.alert('Please enter your card security code (CVV).',"This can be found on the back of your card.")
}
handlePayment();
Platform.OS!=='ios'?myInterval():null;
}}
/>
</View>
</>
);
}
Before webview submission:
after webview submission

React Native Stack Navigation Params

I'm trying to use params on the header of my Image details screen!
Here's a brief explanation.
My user enters an input, I call an api and display the info on the screen:
Home.js
<View style={styles.viewpic}>
<TouchableOpacity onPress={() => navigation.navigate('ImageDetails',
item)}>
<Image
style={{
height: 104,
}}
source={{uri:item.url}}/>
</TouchableOpacity>
</View>
Then, the user clicks on the chosen data, displayed on the screen, and my app navigates to the details page:
ImageDetails.js
export default function ImageDetails({navigation}) {
return(
<ScrollView>
<View>
<Image
source={{uri:navigation.getParam('url')}}/>
<View style={styles.descriptionBox}>
<Text style={styles.imageDet}>Description:{" "}
{navigation.getParam('explanation')}</Text>
</View>
</View>
</ScrollView>
this is the navigation folder I have:
homeStack.js
const screens = {
Home: {
screen: Home,
navigationOptions:{ headerShown: false}
},
ImageDetails: {
screen: ImageDetails,
navigationOptions: () => {
return{
headerTitle: () => <Header/>,
}
}
}
}
const HomeStack = createStackNavigator(screens);
export default createAppContainer(HomeStack);
plus the HEADER component that I'm trying to use in the header navigation (top of the screen):
Header.js
export default function Header({navigation}) {
return(
<View style={styles.descriptionBox}>
<Text style={styles.imageDet}>Params here!</Text>
</View>
)
Here is what the Image detail screen looks like:
My goal is:
to be able to use the data params on the header.
I tried a few different combos but I keep on getting the error: "cant read params"
Some of the things I tried:
Header.js :
export default function Header({navigation}) {
return(
<View style={styles.descriptionBox}>
<Text style={styles.imageDet}>Test:{navigation.getParam('item')}
</Text>
</View>
)
Homestack component:
homeStack.js
const screens = {
Home: {
screen: Home,
navigationOptions:{ headerShown: false}
},
ImageDetails: {
screen: ImageDetails,
navigationOptions: ({navigation}) => {
return{
headerTitle: () => <Header navigation=
{navigation.getParams('title')}/>,
}
}
}
}
const HomeStack = createStackNavigator(screens);
export default createAppContainer(HomeStack);
I also have read the documentation but I'm not sure how I would insert the "Navigation.push" with params here.
Thanks for your help!
try using the existent image details page instead of creating
a new one!
ImageDetails: {
screen: ImageDetails,
navigationOptions: ({navigation}) => {
return{
headerTitle: () => {
return(
<View>
<Text>{navigation.getParam('title')}
</Text>
</View>
)
},

React Native send params between Drawer header and specific screen using header icon

I'm starting with React Native and I would like to open an input search field on a specific screen to filter some results displayed on that screen using the right header icon (search icon).
I was able to use initialParams on Drawer.Screen and I can console.log that param on results screen when the screen loads. I just don't know how to pass this param again (as true) when I click on header icon being on results screen already.
app.routes.tsx:
const Drawer = createDrawerNavigator();
export function AppRoutes() {
const [openFilter, setOpenFilter] = useState(false);
return(
...
<Drawer.Screen
name="Results"
component={Home}
initialParams={{ openFilter: openFilter }}
options={{
headerRight: ({}) => (
<BorderlessButton
onPress={() => {
setOpenFilter(true);
console.log(openFilter);
}}
>
<Feather name="search" size={24} color={theme.colors.heading} style={{ marginRight: 15 }} />
</BorderlessButton>
),
}}
/>;
}
Home.tsx:
export function Home({ route }: any) {
const openFilter = route.params.openFilter;
console.log(openFilter);
const [filter, setFilter] = useState(false); // I would manage filter to be true
return(
...
{filter &&
<View style={{ marginBottom: 24, paddingHorizontal: 10 }}>
<TextInput
style={{ borderBottomColor: 'white', borderBottomWidth: 1 }}
/>
</View>
}
...
I think that if I'd turn openFilterinto true by clicking on header icon I can display the input text. Should I re-render the results screen?
I found a method from navigation that I was using to manage navigation between screens and I can send any params with it:
const Drawer = createDrawerNavigator();
export function AppRoutes() {
const navigation: any = useNavigation();
const [openFilter, setOpenFilter] = useState(false);
return(
...
<Drawer.Screen
name="Results"
component={Home}
initialParams={{ openFilter: openFilter }}
options={{
headerRight: ({}) => (
<BorderlessButton
onPress={() => {
navigation.setParams({ openFilter: openFilter}); // here is the method from navigation
}}
>
<Feather name="search" size={24} color={theme.colors.heading} style={{ marginRight: 15 }} />
</BorderlessButton>
),
}}
/>;
}
And now I can get openFilter or any other param on Home screen.

Stack Navigator in React Native. Error "undefined is not an object (evaluating this.props.navigation)"

It's taking me forever to figure out the obvious, would appreciate some help.
Im using a stack navigator, when a button is pressed it will simply go to another page.
In app.js I created a stack navigator:
const Switcher = createStackNavigator(
{
TaskPg: ListScreen,
AboutPg: AboutScreen
},
{
initialRouteName: "TaskPg",
defaultNavigationOptions: {
title: 'BlueList'
}
}
)
In the ListScreen there is a button the user can press to go to the about page.
const ListScreen = () => {
return (
<View style={styles.container}>
{/* add task component with date picker */}
<AddItemModel />
{/* button pressed to goto About Screen */}
<Button
onPress={() => this.props.navigation.navigate(AboutScreen)}
title="About App" />
{/* sign out button linked to firebase log out */}
<TouchableOpacity onPress={() => firebase.auth().signOut()} >
<Text style={styles.button} >Sign Out</Text>
</TouchableOpacity>
</View>
);
}
export default ListScreen
Run code and every time I press the button I get the error undefined is not an object (evaluating this.props.navigation)
Since your ListScreen is a functional component, this.props doesn't exist.
Change your ListScreen declaration to:
const ListScreen = props => {...}
and access your navigation object like this:
props.navigation.navigate(AboutScreen);

React Native Stacknavigation Custom back button on defaultNavigationOptions

I currently have a static navigationOptions on every single page where I override the backbutton. I'm trying to change this so it uses defaultNavigationOptions instead. How do I access the back functionality of the navigationstack from the navigation file itself?
Current code:
const LoginNavigator = createStackNavigator(
{
// screens
},
{
headerLeft: (
<TouchableHighlight
onPress={() => /* navigate back */}
style={{ alignSelf: "center", marginLeft: 10 }}
>
<FontAwesomeIcon icon={faArrowLeft} color="#ffffff" />
</TouchableHighlight>
)
}
}
);
export const LoginNavigation = createAppContainer(LoginNavigator);
This gets imported into the main app, may that help.

Categories

Resources