Reputation: 1134
I want to use context API in the navigation drawer and I am stuck in how to do that?
I have two screens Display screen and upload screen, in upload screen i am collecting data and sending them to useState hooks and then onlick sending them to display screen . in display screen i a adding this data into array now problem is when i go back upload screen again to send more data display screen array gets return to it's initial state which is empty. Now i need to create a context api so that i can add data in it . How can i do that. Below is my code:
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import { StyleSheet, Text, View } from 'react-native'
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createDrawerNavigator } from '@react-navigation/drawer';
import Upload from './screens/Upload';
import Display from './screens/Display';
const Drawer = createDrawerNavigator();
const App = () => {
return (
<NavigationContainer>
<Drawer.Navigator
initialRouteName='Upload'
screenOptions={{
drawerStyle:{
backgroundColor:"#D8BFD8",
},
drawerActiveBackgroundColor:"#ffffff",
drawerActiveTintColor:"red",
swipeEdgeWidth:300,
drawerHideStatusBarOnOpen:true,
headerShown:true,
headerTitleAlign:"center",
headerStyle:{
backgroundColor:"#0080ff"
},
headerTintColor:"white",
headerTitleStyle:{
fontSize:25,
fontWeight:"bold"
}
}}
>
<Drawer.Screen name="Upload" component={Upload}
options={{
title:"Upload Images"
}}
/>
<Drawer.Screen name="Display" component={Display}
options={{
title:"View Images"
}}
/>
</Drawer.Navigator>
</NavigationContainer>
)
}
const styles = StyleSheet.create({})
export default App
Upload.js
import React, { Fragment, Component, useState,useEffect } from 'react'
import { launchCamera, launchImageLibrary } from "react-native-image-picker"
import { PermissionsAndroid, Pressable, StyleSheet, Text, View,DeviceEventEmitter } from 'react-native'
import { Header, LearnMoreLinks, Colors, DebugInstructons, ReloadInstructions } from 'react-native/Libraries/NewAppScreen'
import { TouchableOpacity } from 'react-native-gesture-handler'
import { Picker } from '@react-native-picker/picker';
import MyContext from './Context'
import { call } from 'react-native-reanimated'
import { ContinousBaseGesture } from 'react-native-gesture-handler/lib/typescript/handlers/gestures/gesture'
const Upload = ({navigation}) => {
const [galleryData, setgallery] = useState({})
const [fileUri, setfileUri] = useState({})
const [Category, setCategory] = useState("")
useEffect(()=>{
setfileUri(
prev => ({
...prev ,newCategory:Category
})
)
},[Category])
const onPressHandler = ()=>{
console.log("this one Picked from picker >>>",Category)
console.log("This one is sent to anoher screen >>>",fileUri["newCategory"])
// DeviceEventEmitter.emit('VariableNameForListener', {MyData: fileUri})
<MyContext.Provider value={}>
{/* // here im stcuk */}
</MyContext.Provider>
navigation.navigate("Display",{MyData:fileUri})
// navigation.navigate("Display")
// setfileUri({})
// setCategory(null)
}
let options = {
storageOptions: {
skipBackup: true,
path: 'images',
},
};
const requestCameraPermission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.CAMERA, {
title: "App Camera Permission",
message: "App needs access to your camera ",
buttonNeutral: "Ask Me Later",
buttonNegative: "Cancel",
buttonPositive: "OK"
}
)
if (granted == PermissionsAndroid.RESULTS.GRANTED) {
launchCamera(options, (response) => {
console.log("Camera launched")
if (response.didCancel) {
console.log("Cancelled By User")
} else if (response.error) {
console.log("Image error")
} else if (response.customButton) {
alert(response.customButton)
} else {
// const source = { setfileUri(prev =>({...prev,["data"]})): response.uri }
setfileUri(
prev => ({
...prev, "data": response["assets"]
})
// ...fileUri,...response
)
}
})
}
} catch (err) {
console.log(err)
}
}
const libraryPicker = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.CAMERA, {
title: "App Camera Permission",
message: "App needs access to your camera ",
buttonNeutral: "Ask Me Later",
buttonNegative: "Cancel",
buttonPositive: "OK"
}
)
if (granted == PermissionsAndroid.RESULTS.GRANTED) {
launchImageLibrary(options, (response) => {
console.log("Camera launched")
if (response.didCancel) {
console.log("Cancelled By User")
} else if (response.error) {
console.log("Image error")
} else if (response.customButton) {
alert(response.customButton)
} else {
// const source = { setfileUri: response.uri }
console.log(JSON.stringify(response))
}
})
}
} catch (err) {
console.log(err)
}
}
return (
<View style={styles.body}>
<View >
<TouchableOpacity onPress={requestCameraPermission} style={styles.btnSection}>
<Text style={styles.text}>
Choose File
</Text>
</TouchableOpacity>
</View>
<View >
<TouchableOpacity onPress={libraryPicker} style={styles.btnSection}>
<Text style={styles.text}>
choose from Gallery
</Text>
</TouchableOpacity>
</View>
<View>
<Picker
selectedValue={Category}
onValueChange={(itemValue, itemIndex) =>
setCategory(itemValue)
}
style={styles.pickerSection}
dropdownIconColor={"#000"}
>
<Picker.Item label='Flowers' value="Flowers" ></Picker.Item>
<Picker.Item label='Cars' value="Cars" ></Picker.Item>
<Picker.Item label='Space' value="Space" ></Picker.Item>
<Picker.Item label='Technology' value="Technology" ></Picker.Item>
<Picker.Item label='Locations' value="Locations" ></Picker.Item>
</Picker>
</View>
<View>
<Pressable
onPress={onPressHandler}
style={[({presses}) => ({backgroundColor:presses ? "Red":"grey"}),styles.btnSection]}>
<Text style={styles.text}>
Press me
</Text>
</Pressable>
</View>
</View>
)
}
const styles = StyleSheet.create({
body: {
flexDirection: "column",
justifyContent: "center",
alignItems: "center"
},
text: {
color: "red",
fontSize: 14,
fontWeight: "bold"
},
btnSection: {
width: 200,
height: 100,
backgroundColor: "#DCDCDC",
justifyContent: "center",
alignItems: "center",
borderRadius: 50,
margin: 20
},
pickerSection:{
width:200,
height:100,
backgroundColor:"red",
justifyContent:"center",
alignItems:"center",
borderRadius:50,
margin:20
},
uploadButton:{
width: 200,
height: 100,
textAlign:"center",
alignItems:"center",
borderRadius:50
}
})
export default Upload
Display.js
import React, { useEffect, useState } from 'react'
import { DeviceEventEmitter, Image, StyleSheet, Text, View } from 'react-native'
const Display = ({navigation,route}) => {
// const [data, setData] = React.useState()
// React.useLayoutEffect(() => {
// DeviceEventEmitter.addListener("VariableNameForListener",emittedData=>{
// setData(emittedData["MyData"]["data"])
// })
// return () => {
// DeviceEventEmitter.removeAllListeners()
// };
// }, [])
const data = route.params;
const Data = data["MyData"]["data"]
const Category = data["MyData"]["newCategory"]
console.log(Data,Category)
//now what we have to do we need to create an object and for values we will use [] to keep on adding data if there is new data added
let myObj = [
{ Locations:[] },
{ Cars:[] },
{ Space:[] },
{ Technology:[] },
{ Flowers:[] },
]
for (let i = 0;i<myObj.length;i++){
console.log(">>",Object.keys( myObj[i])[0])
if ( Object.keys( myObj[i])[0]===Category){
myObj[i][Category].push(Data[0].uri)
}
}
console.log(data)
return (
<View>
{/* <Image
source={{uri:Data[0].uri}}
style={{ width: 500, height: 500 }}
></Image> */}
<Text>okk</Text>
</View>
)
}
const styles = StyleSheet.create({})
export default Display
my Context.js
import React from "react"
const MyContext = React.createContext({})
export default MyContext
Upvotes: 2
Views: 809
Reputation: 442
Here is the link for more about context (works no differently in navigation components): https://reactjs.org/docs/context.html
Now, context is overkill for what you are trying to do. What you're doing now is fine for the most part (though hard to read). The problem, however, is that when you're using navigation, the components are rendered with the navigation container. So calling navigation.navigate("Display",MyData:fileUri})
from Upload.js does nothing to re-render the Display component state.
One way to implement this is instead of receiving the route data w just an assignment operator:
const Category = data["MyData"]["newCategory"]
, use the useState hook in the Display component so it knows when to update the screen. Also, since the route data is not initialized when you navigate to Display.js (navigation.navigate...
) from Upload.js, you can use navigation's focus listener hook so the component knows to update the state:
const [data, setData] = useState({});
navigation.addListener('focus', () => {
const dataFromUpload = route.params;
setData(dataFromUpload["MyData"]["data"]);
});
Upvotes: 2