React Native Stack Navigator passing props - react-navigation

I want to pass some props (value) to another page and I'm using stackNavigator
App.js:
import Insert from "./components/pages/Insert";
import ViewData from "./components/pages/ViewData";
const Stack = createStackNavigator();
NavigationContainer>
<Stack.Navigator headerMode={false}>
<Stack.Screen name="Insert Your data" component={Insert} />
<Stack.Screen name="ViewData" component={ViewData} />
</Stack.Navigator>
</NavigationContainer>
Insert.js
const Insert = ({ props, navigation: { navigate } }) => {
const [enteredName, setEnteredName] = useState();
const [enteredSurname, setEnteredSurname] = useState();
const sendValues = (enteredName, enteredSurname) => {
setEnteredName(enteredName);
setEnteredSurname(enteredSurname);
navigate("ViewData", {
name: enteredSurname,
surname: enteredSurname
});
};
...
<View>
<Button
title="Submit"
onPress={() => sendValues(enteredName, enteredSurname)}
/>
ViewData.js
const ViewData = ({props, navigation: { goBack } }) => {
let name = enteredName;
console.log(name); /// I always get undefined
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Here {name}</Text>
<Button onPress={() => goBack()} title="Edit Data" />
</View>
);
};
When I Submit I'm always getting undefined into the console.
For sure I'm mistaking somewhere.
Any idea?
Thanks!!

Refer to https://reactnavigation.org/docs/hello-react-navigation/#passing-additional-props
Use a render callback for the screen instead of specifying a component
prop:
<Stack.Screen name="Home">
{props => <HomeScreen {...props} extraData={someData} />}
</Stack.Screen>
You can change like this
import Insert from "./components/pages/Insert";
import ViewData from "./components/pages/ViewData";
const Stack = createStackNavigator();
<NavigationContainer>
<Stack.Navigator headerMode={false}>
<Stack.Screen name="Insert Your data">
{props => (<Insert {...props} extraData={data}/>)}
<Stack.Screen name="ViewData" component={ViewData} />
</Stack.Navigator>
</NavigationContainer>

Reading your code it seems that you want to pass some params to the render component when navigate.
Refer to https://reactnavigation.org/docs/route-prop , the params from
navigation.navigate(routeName, params)
are passed to the screen render component as propriety of the route object. So in your case it should work:
let name = props.route.params.name;

Related

React Native Expo (Image Picker) is not displaying the Images

Please help me out with this problem.
I can able to pick the image from my Local storage. In the Console also it is showing, But I cannot able to display it on the screen.
Here is my code.
import * as ImagePicker from "expo-image-picker";
import React, { useState } from "react";
import {
ActivityIndicator,
Button,
FlatList,
Image,
StyleSheet,
Text,
useWindowDimensions,
View
} from "react-native";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
export default function App() {
const [images, setImages] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const pickImages = async () => {
// No permissions request is necessary for launching the image library
setIsLoading(true);
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
// allowsEditing: true,
allowsMultipleSelection: true,
selectionLimit: 10,
aspect: [4, 3],
quality: 1,
});
setIsLoading(false);
console.log(result);
if (!result.canceled) {
setImages(result.uri ? [result.uri] : result.selected);
}
};
return (
<>
<FlatList
data={images}
renderItem={({ item }) => (
<Image
source={{ uri: item.uri }}
style={{ width: 100, height: 100 }}
/>
)}
keyExtractor={(item) => item.uri}
contentContainerStyle={{ marginVertical: 50, paddingBottom: 50 }}
ListHeaderComponent={
isLoading ? (
<View>
<Text
style={{ fontSize: 20, fontWeight: "bold", textAlign: "center" }}
>
Loading...
</Text>
<ActivityIndicator size={"large"} />
</View>
) : (
<Button title="Pick images" onPress={pickImages} />
)
}
/>
</>
);
}
I can able to pick the image from my Local storage. In Console also it is showing, But i cannot able to display it in screen.
Kindly help me out.
It looks like you're already passing the uri into the array. by doing [result.uri] and then in the image you're doing it again item.uri. trying just doing the item.

React Navigation animation from Drawer to Stack

I have some Drawer navigation
<Drawer.Navigator
screenOptions={
drawerStatus ? screenOptions : {...screenOptions, swipeEnabled: false}
}
drawerContent={props => <CustomDrawer {...props} />}
initialRouteName={'Main'}>
{screens.map(screen => (
<Drawer.Screen
key={screen.name}
name={screen.name}
component={screen.component}
/>
))}
</Drawer.Navigator>
And in this Drawer I have a nested screen "Post Detail"
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name={'PostDetail'} component={PostDetail} />
</Stack.Navigator>
If I navigate from Drawer to nested StackScreen or go back to Drawer, I don`t catch animation transition.
Apparently, using only the 'createDrawerNavigator', it is not possible to change the screen transition animation. For this, you must create a 'createStackNavigator', inserting your DrawerNavigator in your 'Home'. Do like:
import React from 'react';
import Home from '../pages/home/home';
import HeaderHome from '../shared/headerHome';
import Configuracoes from '../pages/configuracoes';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { createStackNavigator } from '#react-navigation/stack';
import { DrawerContent } from '../shared/drawerContent';
const Drawer = createDrawerNavigator();
const Content = (navigation: any) => (
<Drawer.Navigator
drawerContent={props => <DrawerContent {...props} />}
>
<Drawer.Screen name="HomeDrawer" component={Home}
options={{
header: (props) => <HeaderHome value={props} /> //My cystom Header
}}
/>
</Drawer.Navigator>
);
const Stack = createStackNavigator();
const MyStack: React.FC = () => {
return (
<Stack.Navigator
screenOptions={({ route, navigation }) => ({
headerMode: "float",
animationEnabled: true
})}
>
<Stack.Screen name="Home" component={Content} //The name used cannot be identical to the one used in Drawer.Navigator
options={{ headerShown: false }}
/>
<Stack.Screen name="Configuracoes" component={Configuracoes}
options={{
title: "Title page",
headerStyle: {
backgroundColor: "red",
},
headerTintColor: "#fff"
}}
/>
</Stack.Navigator>
);
}
export default MyStack;

React-navigation focus on input blurs immediately when going back to previous screen

I want to focus on a textinput when I navigate to a new screen. This works when I add a screen to the stack, but not when I go back in the stack.
Instead, the input focuses for a second and blurs immediately.
Here is what I get:
Screen A is first in the stack and input blurs immediately
Screen B is added to the stack and works as intended
Any idea what is causing this?
FYI, I have the same issue if I use autoFocus.
Here is the whole (pretty straight forward) code:
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import * as React from "react";
import { TextInput, View, Button, Text } from "react-native";
function ScreenA({ navigation }) {
const textInputRef = React.useRef();
const focusOnInput = e => {
textInputRef.current.focus();
};
navigation.addListener("focus", focusOnInput);
return (
<View>
<Text>SCREEN A</Text>
<TextInput ref={textInputRef} />
<Button title="Go to screen B" onPress={() => navigation.navigate("ScreenB")} />
</View>
);
}
function ScreenB({ navigation }) {
const textInputRef = React.useRef();
const focusOnInput = e => {
textInputRef.current.focus();
};
navigation.addListener("focus", focusOnInput);
return (
<View>
<Text>SCREEN B</Text>
<TextInput ref={textInputRef} />
<Button title="Go to screen A" onPress={() => navigation.navigate("ScreenA")} />
</View>
);
}
const Stack = createStackNavigator();
function TestComp() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen component={ScreenA} name="ScreenA" />
<Stack.Screen component={ScreenB} name="ScreenB" />
</Stack.Navigator>
</NavigationContainer>
);
}
export default TestComp;

I can't set transparent modal due to useIsFocused hook

A stack navigator that lives on a bottom tab contains 2 screens. One screen implements the react-native-camera and the other a modal. I'm trying to make the modal transparent but it fails (it has a white background). That's happening because of the useIsFocused hook that mounts and unmounts my camera component. Do you have any suggestions on how I can solve the issue?
function Scanner(){
return(
<Scan.Navigator headerMode='none' mode='modal'
screenOptions={{
cardStyle: { backgroundColor: 'transparent'},
cardOverlayEnabled: true,
}}
>
<Scan.Screen name='Camera' component={Camera}/>
<Scan.Screen name='ValidationModal' component= {Validation} />
</Scan.Navigator>
)
}
Camera = ({navigation}) => {
const [flash, setFlash] = React.useState(false)
const isFocused = useIsFocused();
const flashOn = ()=> {
setFlash(prevFlash => !prevFlash)
}
barcodeRecognized = ({ barcodes }) => {
barcodes.forEach(barcode => {
const kappa = JSON.parse(barcode.data)
navigation.navigate('ValidationMdal')
})
};
if(isFocused){
return(
<RNCamera
ref={ref => {
this.camera = ref;
}}
type={RNCamera.Constants.Type.back}
captureAudio={false}
flashMode={flash?RNCamera.Constants.FlashMode.torch:RNCamera.Constants.FlashMode.off}
androidCameraPermissionOptions={{
title: 'Permission to use camera',
message: 'We need your permission to use your camera',
buttonPositive: 'Ok',
buttonNegative: 'Cancel',
}}
style={{ flex: 1,width: '100%'}}
onGoogleVisionBarcodesDetected={this.barcodeRecognized}>
<TouchableHighlight style={{position:'absolute', top:10, right:10, borderRadius:50, zIndex:100, backgroundColor:'rgba(255,255,255,0.7)'}} onPress={flashOn} >
<Image source={flash?require("../../images/_Active.png"):require("../../images/_Idle.png")} />
</TouchableHighlight>
</RNCamera>
)
}else if(!isFocused){
return null
}
}
Validation = ({navigation}) =>{
return(
<View style={styles.container}>
<Image style={{flex:1}} source={require('../../green-tick.png')} resizeMode={'contain'} />
<TouchableHighlight style={} title='Dismiss' onPress={()=>navigation.goBack()}>
<Text>OK</Text>
</TouchableHighlight>
</View>
)
}

React-Native refs undefined on text input

we are currently running React-Native 0.33
We are trying to use the refs to go from 1 text input to another when they hit the next button. Classic username to password.
Anyone have any idea? Below is the code we are using. From other posts I've found on stack this is what they've done; however, it's telling us that this.refs is undefined.
UPDATE
So I've narrowed the problem down to
render() {
return (
<Navigator
renderScene={this.renderScene.bind(this)}
navigator={this.props.navigator}
navigationBar={
<Navigator.NavigationBar style={{backgroundColor: 'transparent'}}
routeMapper={NavigationBarRouteMapper} />
} />
);
}
If I just render the code below in the renderScene function inside of the original render it works, however with the navigator it won't work. Does anyone know why? Or how to have the navigator show as well as render the code in renderScene to appear in the original render?
class LoginIOS extends Component{
constructor(props) {
super(props);
this.state={
username: '',
password: '',
myKey: '',
};
}
render() {
return (
<Navigator
renderScene={this.renderScene.bind(this)}
navigator={this.props.navigator}
navigationBar={
<Navigator.NavigationBar style={{backgroundColor: 'transparent'}}
routeMapper={NavigationBarRouteMapper} />
} />
);
}
renderScene() {
return (
<View style={styles.credentialContainer}>
<View style={styles.inputContainer}>
<Icon style={styles.inputPassword} name="person" size={28} color="#FFCD00" />
<View style={{flexDirection: 'row', flex: 1, marginLeft: 2, marginRight: 2, borderBottomColor: '#e0e0e0', borderBottomWidth: 2}}>
<TextInput
ref = "FirstInput"
style={styles.input}
placeholder="Username"
autoCorrect={false}
autoCapitalize="none"
returnKeyType="next"
placeholderTextColor="#e0e0e0"
onChangeText={(text) => this.setState({username: text})}
value={this.state.username}
onSubmitEditing={(event) => {
this.refs.SecondInput.focus();
}}
>
</TextInput>
</View>
</View>
<View style={styles.inputContainer}>
<Icon style={styles.inputPassword} name="lock" size={28} color="#FFCD00" />
<View style={{flexDirection: 'row', flex: 1, marginLeft: 2, marginRight: 2, borderBottomColor: '#e0e0e0', borderBottomWidth: 2}}>
<TextInput
ref = "SecondInput"
style={styles.input}
placeholder="Password"
autoCorrect={false}
secureTextEntry={true}
placeholderTextColor="#e0e0e0"
onChangeText={(text) => this.setState({password: text})}
value={this.state.password}
returnKeyType="done"
onSubmitEditing={(event)=> {
this.login();
}}
focus={this.state.focusPassword}
>
</TextInput>
</View>
</View>
</View>
);
}
Try setting the reference using a function. Like this:
<TextInput ref={(ref) => { this.FirstInput = ref; }} />
Then you can access to the reference with this.FirstInput instead of this.refs.FirstInput
For a functional component using the useRef hook. You can use achieve this easily, with...
import React, { useRef } from 'react';
import { TextInput, } from 'react-native';
function MyTextInput(){
const textInputRef = useRef<TextInput>(null);;
return (
<TextInput ref={textInputRef} />
)
}
Try changing the Navigator's renderScene callback to the following (based on Navigator documentation) cause you will need the navigator object later.
renderScene={(route, navigator) => this.renderScene(route, navigator)}
Then, use 'navigator' instead of 'this' to get the refs.
navigator.refs.SecondInput.focus()

Resources