I am using react-native-camera for the first time and I am using functional component for that. I want to open the camera on button click but using the ref is not working. Here is my code :
const camContainer = () => {
const cameraRef = useRef(null);
useEffect(() => {
console.log(cameraRef);
}, [cameraRef]);
const openCamera = () => {
const options = {quality: 0.5, base64: true};
// cameraRef.current.takePictureAsync(options);
console.log(cameraRef);
};
return (
<TouchableOpacity onPress={() => openCamera()}>
<Text>Open Camera</Text>
{!cameraRef && (
<View>
<RNCamera ref={cameraRef} style={{flex: 1, alignItems: 'center'}} />
</View>
)}
</TouchableOpacity>
);
};
I logged cameraRef using useEffect but the cameraRef.current was still null, I cannot understand how do I open the camera then ?
in docs of RNCamera, it should be like this
<Camera
ref={ref => {
this.camera = ref;
}}
/>;
// ...
snap = async () => {
if (this.camera) {
let photo = await this.camera.takePictureAsync();
}
};
Related
I am trying to use React's context hook to store data that is filled out throughout different components. The data is then packaged together and sent to firebase. All of the variables states are changing as expected except for one, the exercise name.
Context
export const PrContext = createContext({});
export const PrProvider = ({children}) => {
const [numExercises,setNumExercises] = useState(0);
const [exercise,setExercise] = useState('Select Exercise');
const [reps,setReps] = useState('');
const [weight, setWeight] = useState('');
const [notes,setNotes] = useState('default note');
const todayDate = getCurrentDate();
return(
<PrContext.Provider
value = {{
numExercises,
setNumExercises,
exercise,
setExercise,
reps,
setReps,
weight,
setWeight,
notes,
setNotes,
sendPrData: async () => {
try {
await setDoc(doc(db,'UsersData',userInfo.user),{
Exercise:{exercise},
Reps:{reps},
Weight:{weight},
});
}catch(e){
console.log(e)
}
},
}}
>
{children}
</PrContext.Provider>
)
}
The screen that holds the components
const PrEnteryScreen = ({}) => {
return(
<View style = {{height:'100%',width:'100%',backgroundColor:'#141212'}}>
<SafeAreaView style = {{alignItems:'center'}}>
{/**
* use context for pr information
*/}
<PrProvider>
<PopDown/>
<RepsWeightTextInput/>
<NotesInput/>
<SubmitPr />
</PrProvider>
</SafeAreaView>
</View>
);
};
export default PrEnteryScreen;
Component whose text I want to change
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const PopDown = () => {
const value = useContext(PrContext)
const [isOpen,setIsOpen] = useState(false)
const [listHeight,setListHeight] = useState(0)
const [textName,setTextName] = useState()
//eventually want to change text based on exercise state
const toggleOpen = ({}) => {
setIsOpen(value => !value);
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
}
useEffect(() =>{
setTextName(value.exercise);
},[value.exercise])
useEffect(() =>{
EXERCISE_DATA.forEach(()=>{
setListHeight(value => value+50)
})
},[isOpen])
return(
<View>
<TouchableOpacity
onPress = {toggleOpen}
>
<View
style={styles.buttonBackground}
>
<Text style = {styles.Text}>{textName}</Text>
</View>
</TouchableOpacity>
<View style = {{alignItems:'center'}}>
<SelectExerciseModal style = {isOpen ? styles.show: styles.hidden} listHeight = {listHeight} />
</View>
</View>
)
}
const styles = StyleSheet.create({
hidden:{
height:0,
},
show:{ backgroundColor: '#9B9A9A', width: 250 , borderRadius: 20},
buttonBackground:{
backgroundColor: '#9B9A9A',
width: 335,
borderRadius:41,
alignItems:'center',
marginHorizontal:25,
height:200,
justifyContent:'center'
},
Text:{
fontWeight:'bold',
fontSize:40,
color:'white',
alignItems:'center'
}
});
export default PopDown;
When I change value.exercise the change is not registered in the popdown component and the text does not change.
list of options component
This component pops out of the popdown component and provides a list of exercises to choose from.
export const EXERCISE_DATA = [
'Bench',
'Squat',
'Deadlift',
]
const SelectExerciseModal = ({listHeight,style}) =>{
return(
<View style = {[style,listHeight]}>
<View style={{
alignItems: 'center',
justifyContent:'center'
}}>
<PrProvider>
<FlatList
data={EXERCISE_DATA}
keyExtractor={item => item}
renderItem={({ item }) => <ExerciseListComponent exerciseName={item} />} />
</PrProvider>
</View>
</View>
)
}
export default SelectExerciseModal;
Exercise list component
const ExerciseListComponent = ({exerciseName}) => {
const value = useContext(PrContext);
useEffect(()=>{
console.log(value.exercise)
},[value.exercise])
return(
<View>
<TouchableOpacity
onPress={()=>{{value.setExercise(exerciseName)}}}
>
<Text style = {styles.text}>
{exerciseName}
</Text>
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
text:{
fontSize:56,
color:'white'
},
})
export default ExerciseListComponent;
const SubmitPr = () => {
const value = useContext(PrContext);
const [Reps,SetReps] = useState('');
const [Exercise,SetExercise] = useState('Select a Exercise');
const [Weight, SetWeight] = useState('');
const [email,setEmail] = useState('not working');
const auth = useContext(AuthContext)
const getInfo = useCallback(()=>{
SetReps(value.reps);
SetExercise(value.exercise);
SetWeight(value.weight);
setEmail(auth.user);
console.log(props.state)
});
const date = getCurrentDate();
return(
<TouchableOpacity
onPress={async () => {
getInfo()
try {
await setDoc(doc(db,'UsersData',date),{
Exercise:{Exercise},
Reps:{Reps},
Weight:{Weight},
});
}catch(e){
console.log(e)
}
}}
>
<View style = {styles.submitButton}>
<Text style = {styles.textStyle}>Submit</Text>
</View>
</TouchableOpacity>
)
};
styles = StyleSheet.create({
submitButton:{
width:209,
height:100,
backgroundColor:'#9B9A9A',
borderRadius:80,
justifyContent:'center',
alignItems:'center',
marginTop:50
},
textStyle:{
color:'white',
fontSize:30,
fontWeight:'bold'
}
})
export default SubmitPr;
Additional Info:
When i press one of the exercise list components it logs the new state of value.exercise through the useEffect hook but when I go to press submit the state of value.exercise is unchanged. Additionally the popdown component's text isn't changing to the new state of value.exercise.
this is my
homePage
as you can see I have some items and a button that I use to add them to the chartScreen, which is chartScreen , I'm using context api to store items in cartContext.js where each item has its own key to make things easier but I cannot correlate the logic for how to assign each item to the button so whenever I press the button its own item gets added to the chartScreen.
const CartContext = createContext();
export function CartProvider({ children }){
const [items, setItems] = useState(
[
{
title: "Pınar",
text: "Pınar Klasik Dana Sucuk (225g)",
pic: <Image
style={styles.image1}
source={require("./Images/klasik_dana_sucuk_paket.png")} />,
key: 1,
},
{
text: "Pınar Uzun Sosis (225g)",
pic: <Image
style={styles.image1}
source={require("./Images/pinar_uzun_sosis.png")} />,
key: 2,
},
]
const [store, setStore] = useState([]);
const addToCart = (text) => {
setStore((prevState) => [
...prevState,
text,
]);
}
return (
<CartContext.Provider value={{items,setItems, addToCart, store}}>
{children}
</CartContext.Provider>
)
I found a cheeky way to send a specific item from addButton.js
const AddButton = () => {
const { items } = useContext(CartContext);
const { addToCart } = useContext(CartContext);
return (
<TouchableOpacity style={styles.button} onPress={() => addToCart(items[0])}>
<Text>+</Text>
</TouchableOpacity>
)
}
and in the chartScreen I view it just like this
const ChartScreen = () => {
const { store } = useContext(CartContext);
if(store.length != 0) {
return (
<FlatList
data={store}
renderItem={({ item }) => (
<View style={styles.listItem}>
<Text style={styles.itemText}>{item.pic} {item.text}</Text>
</View>
)}
/>
)
}
this is for sure not even the wrong way to achieve the goal so can you help me?
You can import your button and make it common for all the items, and pass the value to it.
Here is your button code
const AddButton = ({item}) => {
const { items } = useContext(CartContext);
const { addToCart } = useContext(CartContext);
return (
<TouchableOpacity style={styles.button} onPress={() =>
addToCart(item?.text)}>
<Text>+</Text>
</TouchableOpacity>
)
}
Here you can make button for all you item
const ChartScreen = () => {
const { store } = useContext(CartContext);
if(store.length != 0) {
return (
<FlatList
data={store}
renderItem={({ item }) => (
<View style={styles.listItem}>
<Text style={styles.itemText}>{item.pic} {item.text}</Text>
<AddButton item={item} />
</View>
)}
/>
)
}
Im trying to make a feature for my app where the user can fill a questionnaire with radio buttons and he can save the progress and can return later to finish it.
Take a look at this code:
const Step3 = () => {
const [questions, setQuestions] = useState([]);
const [answers, setAnswers] = useState([]);
const {addQuest} = useContext(AuthContext);
const getQuestions = async () => {
const locale = 'sq'; // TODO: get current locale
const response = await apiStandarts.get(`/questions?locale=${locale}`, {
params: { _limit: MAX_QUESTIONS, active: 1, _sort:'sortId:ASC' },
});
setQuestions(response.data);
};
const isOptionSelected = (option) => {
const answer = answers[option.question]
if (answer) {
return option.id == answer.id
}
return false;
}
const saveData = () =>{
AsyncStorage.setItem('questions', JSON.stringify(answers)).then(() => {
console.log('data saved', answers)
}).catch((error) => {
console.log(error)
})}
const retrieveData = async () => {
try {
const answers = await AsyncStorage.getItem('questions');
const parsed = JSON.parse(answers);
Alert.alert(`${parsed.id}`);
} catch(error) {
Alert.alert(error)
}
}
useEffect(() => {
getQuestions();
}, []);
const OptionList = (groupOption) => {
return (
<FlatList
data={groupOption.options}
keyExtractor={(result) => result.id.toString()}
renderItem={({ item, index}) => {
const clickedRadio = () => {
const selectedOption = {[item.question]:{...item}}
setAnswers({...answers, ...selectedOption})
console.log(answers)
}
const status = isOptionSelected(item) ? true : false
return (
<View key={index}>
<Radio initialValue={status} label={item.description} onChange={() => clickedRadio()}/>
</View>
);
}}
/>
);
};
return (
<View style={styles.container}>
<Text style={{ fontWeight: "bold", fontSize: 16, color: "#6B24AA" }}>
{t("Choose an option/Scroll for more questions")}
</Text>
<FlatList
data={questions}
keyExtractor={(result) => result.id.toString()}
renderItem={({ item, index }) => {
return (
<View style={styles.groupOptions} key={index}>
<Text>{item.description}</Text>
<OptionList options={item?.question_options}></OptionList>
</View>
);
}}
/>
<Button onPress={() => addQuest({answers})}>Save progress</Button>
<Button onPress={() => retrieveData()}>Get progress</Button>
</View>
)
}
I've tried with AsyncStorage but i get my questions from an API and the data re-renders every time the app opens again. Any ideas how to achieve this ? Thanks in advance
I'm trying to display a bunch of data i have on firebase in a flatlist, I don't really know where the problem is right now, i've tried physically filling the array out and that works but it doesn't when i get the data from firebase. I do see that im getting the data on the console log but it's not getting displayed.
function Squad() {
const gk = [];
db.collection('squad').orderBy('position').get().then(snapshot => {
snapshot.forEach(doc => {
const playerObject = doc.data();
gk.push({name: playerObject.name, number: playerObject.number});
console.log(gk);
});
});
const Item = ({ name, number }) => (
<View style={styles.item}>
<Text style={styles.itemText}>{number} - {name}</Text>
</View>
);
const renderItem = ({ item }) => (
<Item name={item.name} number={item.number} />
)
return(
<View>
<View style={styles.bar}>
<Text style={styles.barText}>goalkeeper</Text>
</View>
<FlatList
data={gk}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</View>
)
}
You can get the info on mount in an async function, then store it in a stateful array using hooks.
function Squad() {
const [gk, setGk] = useState([]);
const getSquad = async () => {
const ref = db.collection('squad').orderBy('position');
const doc = await ref.get();
const playerObject = doc.data();
const newGk = [...gk, {name: playerObject.name, number: playerObject.number}];
setGk(newGk);
}
useEffect(() => {
getSquad();
}, [])
const Item = ({ name, number }) => (
<View style={styles.item}>
<Text style={styles.itemText}>{number} - {name}</Text>
</View>
);
const renderItem = ({ item }) => (
<Item name={item.name} number={item.number} />
)
return(
<View>
<View style={styles.bar}>
<Text style={styles.barText}>goalkeeper</Text>
</View>
<FlatList
data={gk}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</View>
)
}
Start by creating a useEffect hook to act as a componentWillMount function to call the method when the compnent is ready. I have also included catch block in order to show any errors that might occur.
import React, { useState, useEffect } from "react";
const Squad = () => {
const [gk, setGK] = useState([]);
useEffect(() => {
getSquadData();
});
const getSquadData = () => {
db.collection("squad")
.orderBy("position")
.get()
.then((snapshot) => {
let myData = [];
snapshot.forEach((doc) => {
const playerObject = doc.data();
myData.push({
id: playerObject.id,
name: playerObject.name,
number: playerObject.number,
});
});
setGK(myData);
})
.catch((error) => {
console.log("Error getting data: ", error);
});
};
const Item = ({ name, number }) => (
<View style={styles.item}>
<Text style={styles.itemText}>
{number} - {name}
</Text>
</View>
);
const renderItem = ({ item }) => (
<Item name={item.name} number={item.number} />
);
return (
<View>
<View style={styles.bar}>
<Text style={styles.barText}>goalkeeper</Text>
</View>
<FlatList
data={gk}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
);
};
export default Squad;
So if you are seeing error logs in your console, check your collection in firestore, and also check the rules in your firestore.
is it possible, in a React Native Function, to render the "return" at changes?
What I try:
I have a Function - this Function gets an specific array out of another Function - on Button Press I generate a new Index - now what I want is to re-render the View to display the array element with the new Index:
const generateNewIndex = function (item) {
return Math.floor(Math.random() * item.length);
};
const PositionItem = ({ arr, position, navigation }) => {
let { name, beschreibung, arten, rooms, isStarred } = position;
let testArray = arr;
let i = 0;
return (
<View style={styles.posContainer}>
<View style={styles.titles}>
<Text style={styles.title}>{name}</Text>
<Text style={styles.subtitle}>{beschreibung}</Text>
<Text style={styles.title}>{testArray[i].name}</Text>
</View>
<View style={styles.buttonsContainer}>
<StyledButton
type="primary"
content={"Next Random Position"}
onPress={() => {
console.warn("Pressed");
i = generateNewIndex(testArray);
}}
/>
</View>
</View>
);
};
export default PositionItem;
Thanks in advance!
I have found a way which is Working.
If anyone wonders in the Future what I did:
add a Use State component:
const [count, setCount] = useState(0);
onPress on Button increase the Count:
onPress={() => {
i = generateNewIndex(array);
setCount((prevCount) => prevCount + 1);
}}