I'm sure its a stupid mistake somewhere but when I switch between class component to functional (to learn/understand how state works in both of these) I kind of miss the logic sometimes (with this.props etc). (home.js navigates to the page called addDiary.js)
I'm not finished with the async logic/code but don't understand why I get the error "cant find variable: diary" at this point, thank you
Home.js
const Home = ({navigation}) => {
const [refreshing, setRefreshing] = useState(false);
const [diary, setDiary] = useState(null)
whenRefresh = async () => {
try{
setRefreshing(true);
const diary = await AsyncStorage.getItem('diary')
setDiary(JSON.parse('diary'))
setRefreshing(false)}
catch (error) {console.log(error)}
}
return(
<View style={styles.home}>
<ScrollView
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={whenRefresh}/>}
style={styles.body}>
{diary ? <ListItem
title={diary.title}
subtitle="test"
onPress={()=>{console.log("listitem pressed")}}
/> : null}
addDiary.js
const AddDiary = () => {
const [title, setTitle] = useState()
const [body, setBody] = useState()
const submit = async () => {
const diary = {title, body}
await AsyncStorage.setItem('diary', JSON.stringify(diary))
navigation.goBack()
}
return(
<SafeAreaView style={styles.home}>
<View style={styles.group}>
<Text style={styles.label}>Title:</Text>
<TextInput
placeholder="title"
style={styles.titleInput}
onChangeText={setTitle}
value={title}
/>
</View>
<View style={[styles.group, {flex:1}]}>
<Text style={styles.label}>Body:</Text>
<TextInput
placeholder="title"
style={[styles.titleInput, {height: 300}]}
onChangeText={setBody}
value={body}
/>
</View>
<Button
name="check-circle"
size={50}
color="black"
onPress={submit}
/>
</SafeAreaView>
)
}
const submit = async () => {
const diary = {title, body}
await AsyncStorage.setItem('diary',JSON.stringify(diary))
}
Change your submit function to this.
and it should work fine
const Home = ({navigation}) => {
const [refreshing, setRefreshing] = useState(false);
const [diary, setDiary] = useState(null)
whenRefresh = async () => {
setRefreshing(true);
const diary = await AsyncStorage.getItem('diary')
setDiary(JSON.parse('diary'))
setRefreshing(false)
}
return(
<View style={styles.home}>
<ScrollView
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={whenRefresh}/>}
style={styles.body}>
{diary ? <ListItem
title={diary.title}
subtitle="test"
onPress={()=>{console.log("listitem pressed")}}
/> : null}
Related
Does anyone know how I can change the state of a renderItem when it leaves screen? Below I have the Flatlist with uses an Item, I want to change the state of the item once it exits the renderview.
const Item = memo(({content}) => {
const [outOfView, setOutOfView] = useState(false)
const onScroll= () => {
if (!outOfView) setOutOfView(true) //Trying to get this to work
}
return (
<View style={styles.item} onScroll={onScroll}>
<Text>{content.title}</Text>
</View>
)
})
const Slider = props => {
const flatList = useRef()
const _renderItem = ({ item, index }) => <Item content={item} />
return (
<View style={styles.container} >
{props.header ? <AppText style={styles.header} text={props.header} /> : null}
<FlatList
data={props.data}
horizontal
pagingEnabled
renderItem={_renderItem}
keyExtractor={item => item._id}
ref={flatList}
/>
</View>
)
}
YOu can do something like this
import { useIsFocused } from '#react-navigation/native';
const Item = memo(({content}) => {
const [outOfView, setOutOfView] = useState(false)
const onScroll= () => {
if (!outOfView) setOutOfView(true) //Trying to get this to work
}
const isFocused = useIsFocused();
return (
<View style={styles.item} onScroll={onScroll}>
<Text>{isFocused?content.title:"Offline"}</Text>
</View>
)
})
hope it helps. feel free for doubts
I'm making an app that looks for a data in the Firebase database, and if the data exists it appears a Text Input. If the data doesn't exist, it shows another Text Input.
//CODE
function Veic({ navigation, route }) {
const [date, setDate] = useState("");
const database = firebase.firestore()
const [selectedValue, setSelectedValue] = useState("");
const [placa, setPlaca] = useState("");
const [atv, setAtv] = useState("");
const [km, setKm] = useState("");
const [obs, setObs] = useState("");
const [kmF, setKmF] = React.useState("");
const { idUser, user, uid } = route.params;
var auth = firebase.auth();
useEffect(() => { // the rest of the code doesn't read the "values_id"
const DocVeic = query(collection(database, "user_veic"),where("email", "==", auth.currentUser?.email),where("kmF", "==", ""));
getDocs(DocVeic).then((querySnapshot) => {
let values_id = null;
querySnapshot.forEach((doc) => {
values_id = doc.id;
console.log(`${values_id}`);
})
})
},[])
function altInfo(){
const Doc = query(collection(database, "user_veic"),where("email", "==", auth.currentUser?.email),where("kmF", "==", ""));
getDocs(Doc).then((querySnapshot) => {
let values = null;
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${doc.data()}`);
values = doc.id;
});
var transactionUpdate = database.collection("user_veic").doc(values);
transactionUpdate.update({
kmF: kmF,
})
})
}
// ADD A DATA
function addInfo(){
database.collection("user_veic").add({
email: auth.currentUser?.email,
placa: placa,
atv: atv,
km: km,
obs: obs,
dataInicial: data_full,
dataFinal: '',
kmF: '',
});
navigation.navigate('Liber', {idUser: user})
}
return (
<View style={fundoVeic.container}>
<View style={fundoVeic.perfilUser}>
<Text style={{color:'#007831',fontWeight:'bold',fontSize:15,height: 40}}>
<Image style={fundoVeic.imageEnvel} source={require('../../imagens/envelope.png')}/>
<Text style={{color:'#cce4d5'}}>...</Text>{auth.currentUser?.email}
</Text>
</View>
{values_id === null ?
<View>
<TextInput
style={fundoVeic.input}
placeholder='Digite a placa do veículo'
maxLength={7}
placeholderTextColor='#000'
onChangeText={txtPlaca => setPlaca(txtPlaca)}
value={placa}
/>
<TextInput
style={fundoVeic.input}
placeholder='Digite a atividade'
placeholderTextColor='#000'
onChangeText={txtAtv => setAtv(txtAtv)}
value={atv}
/>
<TextInput
style={fundoVeic.input}
keyboardType='numeric'
placeholder='Digite o km do veículo'
placeholderTextColor='#000'
onChangeText={txtKm => setKm(txtKm)}
value={km}
/>
<TextInput
style={fundoVeic.inputObs}
multiline={true}
numberOfLines={5}
placeholder='Observação (opcional)'
placeholderTextColor='#000'
onChangeText={txtObs => setObs(txtObs)}
value={obs}
/>
<Pressable
style={fundoVeic.button}
onPress={addInfo}
>
<Text style={fundoVeic.textButton}>Selecionar</Text>
</Pressable>
</View>
:
<View>
<TextInput
keyboardType='numeric'
placeholder='Digite o km final do veículo'
placeholderTextColor='#000'
onChangeText={txtKmF => setKmF(txtKmF)}
value={kmF}
/>
<Pressable
onPress={altInfo}
>
<Text>Liberar</Text>
</Pressable>
</View>
}
</View>
);
}
export default Veic;
The app has a login. When logging in, enters a screen that will appear a certain text and input (with a condition). The condition: if the variable "kmf", in Firebase, is empty, it shows an input on the screen for the user to put a km. When the user writes the km, the data is updated. The problem is that I am not able to make a condition that reads the "values_id". What is the solution?
values_id is not component state. In fact the variable only exists inside the useEffect function and is not available anywhere else. Add it to the component state with useState.
const [valuesId, setValuesId] = useState<string>(null);
useEffect(() => {
// ...
setValuesId(doc.id);
},[])
when redirecting to index screen after submitting a post-form, the index screen does not show the newly added item in the list, can anyone help?
here is my Customer.js page
export default function Customer({ navigation }) {
const [customers, setCustomers] = useState([]);
const [isLoading, setLoading] = useState(true);
const getCustomers = async () => {
try {
const response = await fetch("http://localhost:3001/api/customers");
const json = await response.json();
setCustomers(json);
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
};
useEffect(() => {
getCustomers();
}, []);
return (
<View style={styles.item}>
<TouchableOpacity
onPress={() => navigation.navigate("AddCustomer")}
style={styles.btn}
>
<Text style={styles.btnText}>Add New Customer</Text>
</TouchableOpacity>
<FlatList
data={customers}
extraData={customers}
renderItem={({ item }) => (
<TouchableOpacity
onPress={() => navigation.navigate("CustomerDetails", item)}
>
<Text style={styles.item}>{item.name}</Text>
</TouchableOpacity>
)}
keyExtractor={(item) => item._id}
/>
</View>
);
}
}
and here is my AddCustomer.js page
const AddCustomer = ({ navigation, route }) => {
const [name, setName] = useState("");
const [phone, setPhone] = useState(0);
const [isGold, setIsGold] = useState(false);
const handleSubmit = async () => {
// e.preventDefault();
return await fetch("http://localhost:3001/api/customers", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: name,
phone: phone,
isGold: isGold,
}),
}).then(() => {
navigation.navigate("Customer", { customers: [name, phone, isGold] });
});
};
return (
<View>
<Text style={styles.title}>Add New Customer</Text>
<View>
<TextInput
style={styles.input}
onChangeText={(val) => setName(val)}
value={name}
placeholder="Your name"
onBlur={Keyboard.dismiss}
/>
<TextInput
style={styles.input}
onChangeText={(val) => setPhone(val)}
value={phone}
placeholder="phone number"
/>
<TextInput
style={styles.input}
onChangeText={(val) => setIsGold(val)}
value={isGold}
placeholder="is gold member"
autoCorrect={false}
autoCapitalize={false}
/>
</View>
<View style={styles.inputContainer}>
<TouchableOpacity style={styles.saveButton} onPress={handleSubmit}>
<Text style={styles.saveButtonText}>Add Customer</Text>
</TouchableOpacity>
</View>
</View>
);
};
new customer would be added and everything else work fine but the Customer page does not get re-rendered or refresh or reload.
In your Customer.js do it like below -
useEffect(() => {
const unsubscribe = navigation.addListener('focus', async () => {
getCustomers();
});
return unsubscribe ;
}, [navigation]);
import { useFocusEffect } from '#react-navigation/native';
useFocusEffect(
React.useCallback(() => {
// Do something when the screen is focused
getCustomers();
return () => {
// Do something when the screen is unfocused
};
}, []),
);
I am trying to change the background color of my react native app based on the current theme, i.e., whether it is dark or light.
Here is my code :
const SignUp = ({navigation}) => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [name, setName] = useState("");
const [secureTextEntry, setSecureTextEntry] = useState(true);
const [error, setError] = useState("")
const clear = () => {
setEmail('')
setPassword('')
setName('')
setError('')
}
function onLinkClick(){
navigation.navigate('login')
clear()
}
async function onButtonPress() {
if(email && password && name){
setError("");
await auth().createUserWithEmailAndPassword(email, password)
.then(() => {
const {currentUser} = auth();
firestore().
collection(`users/${currentUser.uid}/name`)
.add({
name: name
})
clear()
navigation.navigate('login')
})
.catch(() => {
setError("Email already exists!!! Login instead.")
})
}else{
setError("Please fill all the fields");
}
}
var colour = '#1d2447'
const toggleSecureEntry = () => {
if(password){
setSecureTextEntry(!secureTextEntry);
}
};
const renderIcon = (props) => (
<TouchableWithoutFeedback onPress={toggleSecureEntry}>
<Icon {...props} name={secureTextEntry ? 'eye-off' : 'eye'}/>
</TouchableWithoutFeedback>
);
return(
<React.Fragment>
<View style={[styles.containerStyle, {backgroundColor: `${colour}`}]}>
<Text style={styles.textStyle} category='h2'>What should we call</Text>
<Text style={[styles.textStyle, {marginBottom: 10}]} category='h2'>you?</Text>
<Text style={styles.subtextStyle}>You'll need a name to make your</Text>
<Text style={styles.subtextStyle}>own posts, customize your blog,</Text>
<Text style={styles.subtextStyle}>and message people</Text>
<View style={styles.formStyle}>
<Input
style={styles.textInputStyle}
size='large'
placeholder='Email'
value={email}
onChangeText={nextValue => setEmail(nextValue)}
/>
<Input
value={password}
placeholder='Password'
accessoryRight={renderIcon}
secureTextEntry={secureTextEntry}
onChangeText={nextValue => setPassword(nextValue)}
style={styles.textInputStyle}
size="large"
autoCorrect
/>
<Input
value={name}
placeholder='Name'
onChangeText={nextValue => setName(nextValue)}
style={styles.textInputStyle}
size="large"
/>
</View>
<Button style={styles.button} size='medium' status='basic' appearance="outline" onPress={onButtonPress}>Sign Up</Button>
<Text style={styles.errorTextStyle} category='h6'>{error}</Text>
<Text style={styles.linkStyle}>Already have an account?</Text>
<Text style={styles.linkStyle} onPress={() => onLinkClick()}>Login</Text>
</View>
</React.Fragment>
)
Here I want to change the background depending on whether the current theme is dark or light, but I'm not able to fetch it.
sorry for bad English.
My function component not waiting API Function, I'm write async and await and not working again..
"Object are not valid as a React child" error screen...
Please help me :'/
const NormalCarousel = async (props) => {
const navigation = useNavigation();
const [ResponseData, setResponseData] = useState('');
const ComponentAPI = props.api;
const API = await axios.get(ComponentAPI).catch((error) => {alert(error)});
await setResponseData(API);
return(
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false}>
{
ResponseData.map(item => (
<TouchableOpacity style={styles.CarouselTouchable} onPress={() => navigation.navigate("Ürün", {id: item.item_id})}>
<Image
style={styles.CarouselImage}
source={{uri: item?.item_avatar}}
/>
<View style={styles.CarouselView}>
<Text style={styles.CarouselTitle}>{item?.item_name}</Text>
<Text style={styles.CarouselSubtitle}>{item?.item_stock_code}</Text>
</View>
</TouchableOpacity>
))
}
</ScrollView>
)
}
The error is happening because the parent component trying to render this component is actually rendering a Promise which resolves into a component. That's not possible.
You should instead call the function to load the data once on component mount (useEffect). You'll also need to replace useState('') with useState([]) since you're trying to map over this data when rendering.
const NormalCarousel = (props) => {
const { api } = props;
const navigation = useNavigation();
const [responseData, setResponseData] = useState([]);
useEffect(() => {
getAPI();
}, []);
async function getAPI() {
const API = await axios.get(api).catch((error) => alert(error));
setResponseData(API);
}
return(
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
{
responseData.map(item => (
<TouchableOpacity style={styles.CarouselTouchable} onPress={() => navigation.navigate("Ürün", {id: item.item_id})}>
<Image
style={styles.CarouselImage}
source={{uri: item.item_avatar}}
/>
<View style={styles.CarouselView}>
<Text style={styles.CarouselTitle}>{item.item_name}</Text>
<Text style={styles.CarouselSubtitle}>{item.item_stock_code}</Text>
</View>
</TouchableOpacity>
))
}
</ScrollView>
)
}