With my current code, I have two input fields and a drop down menu. When ever a value is placed into the field or modified, it clears the rest of the fields. The only one that will stay consistent is the drop down menu. I have suspicions that my useEffect hooks may be doing something, but I'm quite unsure of why. Any suggestions would be great. (FYI: storeArtic is the push to firebase)
CustomScreen.js
import React, { useState } from "react";
import { StyleSheet, Text, Keyboard, View, TouchableWithoutFeedback } from "react-native";
import { Button, Input } from "react-native-elements";
import { Dropdown } from "react-native-material-dropdown";
import { storeArtic } from '../helpers/fb-settings';
const CustomScreen = ({ route, navigation }) =>{
//create a screen with the ability to add a picture with text to the deck of artic cards
//add check box solution for selection of word type (maybe bubbles, ask about this)
const articDrop = [
{value: 'CV'},
{value: 'VC'},
{value: 'VV'},
{value: 'VCV'},
{value: 'CVCV'},
{value: 'C1V1C1V2'},
{value: 'C1V1C2V2'},
];
const [articCard, setCard] = useState({
word: '',
imageUrl: '',
aType:'',
cType: '',
mastery: false
})
return(
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View>
<Text>Please enter the information of your custom card!</Text>
<Input
placeholder="Enter valid image url"
value={articCard.imageUrl}
autoCorrect={false}
onChangeText={(val) => setCard({ imageUrl: val })}
/>
<Input
placeholder="Enter word or phrase"
value={articCard.word}
autoCorrect={false}
onChangeText={(val) =>
setCard({ word: val, aType: val.charAt(0).toUpperCase(), mastery: false})
}
/>
<Dropdown
value={articCard.cType}
onChangeText={(text) => setCard({cType: text})}
label="Artic Type"
data={articDrop}
/>
<Button
//this will save the cards to the database
title="Save"
onPress={() => {
storeArtic({articCard})
}}
/>
<Button
title="Clear"
onPress={() => {
setCard({word: '', aType: '', cType: '', imageUrl: '', mastery: false});
navigation.navigate('Home');
}}
/>
</View>
</TouchableWithoutFeedback>
)
}
export default CustomScreen;
HomeScreen.js
import React, { useState, useEffect } from "react";
import { StyleSheet, Text, Keyboard, TouchableOpacity, View, TouchableWithoutFeedback, Image } from "react-native";
import { Button } from "react-native-elements";
import { Feather } from "@expo/vector-icons";
import { initArticDB, setupArticListener } from '../helpers/fb-settings';
const HomeScreen = ({route, navigation}) => {
const [ initialDeck, setInitialDeck] = useState([]);
useEffect(() => {
try {
initArticDB();
} catch (err) {
console.log(err);
}
setupArticListener((items) => {
setInitialDeck(items);
});
}, []);
useEffect(() => {
if(route.params?.articCard){
setCard({imageUrl: state.imageUrl, word: state.word, aType: state.aType, cType: state.cType, mastery: state.mastery})
}
}, [route.params?.articType] );
navigation.setOptions({
headerRight: () => (
<TouchableOpacity
onPress={() =>
navigation.navigate('Settings')
}
>
<Feather
style={styles.headerButton}
name="settings"
size={24}
color="#fff"
/>
</TouchableOpacity>
),
headerLeft: () => (
<TouchableOpacity
onPress={() =>
navigation.navigate('About')
}
>
<Text style={styles.headerButton}> About </Text>
</TouchableOpacity>
),
});
return(
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.container}>
<Text style={styles.textmenu}>Welcome to Artic Cards</Text>
<Text style={styles.textsubmenu}>Press Start to Begin!</Text>
<Image source={require('../assets/5-snowflake-png-image.png')}
style={{width: 300, height: 300, alignSelf: 'center'}}/>
<Button
title="Start"
style={styles.buttons}
onPress={() => navigation.navigate('Cards',
{passDeck: initialDeck})}
/>
<Button
title="Progress"
style={styles.buttons}
onPress={() => navigation.navigate('Progress')}
/>
<Button
title="Customize"
style={styles.buttons}
onPress={() => navigation.navigate('Customize')}
/>
</View>
</TouchableWithoutFeedback>
);
};
const styles = StyleSheet.create({
container: {
padding: 10,
backgroundColor: '#E8EAF6',
flex: 1,
justifyContent: 'center'
},
textmenu: {
textAlign: 'center',
fontSize: 30
},
textsubmenu:{
textAlign: 'center',
fontSize: 15
},
headerButton: {
color: '#fff',
fontWeight: 'bold',
margin: 10,
},
buttons: {
padding: 10,
},
inputError: {
color: 'red',
},
input: {
padding: 10,
},
resultsGrid: {
borderColor: '#000',
borderWidth: 1,
},
resultsRow: {
flexDirection: 'row',
borderColor: '#000',
borderBottomWidth: 1,
},
resultsLabelContainer: {
borderRightWidth: 1,
borderRightColor: '#000',
flex: 1,
},
resultsLabelText: {
fontWeight: 'bold',
fontSize: 20,
padding: 10,
},
resultsValueText: {
fontWeight: 'bold',
fontSize: 20,
flex: 1,
padding: 10,
},
});
export default HomeScreen;
Unlike class based setState
, with functional components when you do setState, it will override the state with what you provide inside setState function. It is our responsibility to amend state (not overrite)
So, if your state is an object, use callback approach and spread previous state and then update new state.
Like this
<Input
placeholder="Enter valid image url"
value={articCard.imageUrl}
autoCorrect={false}
onChangeText={(val) => setCard(prev => ({ ...prev, imageUrl: val }))} //<----- like this
/>
Do the same for all your inputs.