I'm using a useState called tripState in my react native component.
const [tripState, setTripState] = useState<NewTripState>({
name: "",
description: "",
thumbnail: "",
});
I change its value in text field using function:
const onChange = (
key: keyof NewTripState,
value: string | null,
): void => {
setTripState({
...tripState,
[key]: value,
});
};
Text input:
<TextInput
value={tripState.name}
onChangeText={(value: string): void => {
onChange("name", value);
}}
placeholder={"Enter trip name"}
/>
which is called on text inputs. If I console.log the value in:
useEffect(() => {
console.log(tripState); // console.logs updated state
}, [tripState]);
it console logs correct (updated) value, but the moment i try to console log it in my onSubmit
method which is called on onPress
on Pressable
, I get the initial value.
<Pressable onPress={onSubmit}>
<Text>Save</Text>
</Pressable>
const onSubmit = () => {
console.log(tripState); // console.logs initial state
};
Can someone please help me? I don't know that to do anymore.
Edit 1: Entire component:
import React, { useEffect, useState } from "react";
import { useColorScheme } from "react-native";
import { getUserHoliday } from "../../api/firestore/trips";
import ProfilePicture from "../../components/ProfilePicture";
import {
View,
Text,
Pressable,
} from "../../components/Themed";
import { tintColorLight } from "../../constants/Colors";
import store from "../../redux/store";
import { getUserId } from "../../redux/stores/user";
import { Holiday } from "../../utils/types/holiday";
import { Trip } from "../../utils/types/trip";
type NewTripScreenProps = {
navigation: any;
route: any;
};
export type NewTripState = {
name: string;
description: string;
thumbnail: string;
};
const NewTripScreen = (props: NewTripScreenProps) => {
const { navigation } = props;
const [tripState, setTripState] = useState<NewTripState>({
name: "",
description: "",
thumbnail: "",
});
useEffect(() => {
console.log(tripState);
}, [tripState]);
const onChange = (
key: keyof NewTripState,
value: string | null,
): void => {
setTripState((currentValue) => ({
...currentValue,
[key]: value,
}));
};
const userId = getUserId(store.getState());
const colorScheme = useColorScheme();
useEffect(() => {
getUserHoliday(userId).then((holidays) => {
setHolidays(holidays);
});
navigation.setOptions({
headerTitle: "New Trip",
headerRight: () => (
<Pressable onPress={onSubmit}>
<Text
style={{
color: tintColorLight,
fontSize: 18,
}}
>
Save
</Text>
</Pressable>
),
headerTintColor: tintColorLight,
headerTitleStyle: {
color: colorScheme === "dark" ? "#fff" : "#000",
},
});
}, []);
const onSubmit = () => {
console.log(tripState.name);
const trip: Trip & { holiday?: Holiday | null } = {
userId: userId,
...tripState,
status: "created",
};
};
return (
<View>
<Text
style={{
fontWeight: "bold",
fontSize: 32,
padding: 10,
}}
>
New Trip
</Text>
<View style={{ alignItems: "center", marginTop: 20 }}>
<TextInput
value={tripState.name}
onChangeText={(value: string): void => {
onChange("name", value);
}}
placeholder={"Enter trip name"}
/>
<TextInput
value={tripState.description}
onChangeText={(value: string): void => {
onChange("description", value);
}}
placeholder={"Enter Description"}
style={{ marginTop: 20 }}
/>
<Text
style={{
fontWeight: "bold",
fontSize: 32,
padding: 10,
}}
>
Thumbnail
</Text>
<ProfilePicture
photoURL={tripState.thumbnail}
onPress={() => {}}
/>
</View>
</View>
);
};
export default NewTripScreen;
CodePudding user response:
It is happening because of useEffect with empty dependency array. When you add onSubmit()
on Pressable's onPress listener, because of useEffect with empty dependency array the original value of tripState inside onSubmit
is used.
Change the code like this
useEffect(() => {
getUserHoliday(userId).then((holidays) => {
setHolidays(holidays);
});
navigation.setOptions({
headerTitle: "New Trip",
headerTintColor: tintColorLight,
headerTitleStyle: {
color: colorScheme === "dark" ? "#fff" : "#000",
},
});
}, []);
useEffect(() => {
navigation.setOptions({
headerRight: () => (
<Pressable onPress={onSubmit}>
<Text
style={{
color: tintColorLight,
fontSize: 18,
}}
>
Save
</Text>
</Pressable>
)
});
}, [tripState]);
CodePudding user response:
The topic you're looking for is called 'stale values'. It's what happens when values get locked in to your function, and don't refresh. React useState has a way of solving this, really simply:
Instead of:
setTripState({
...tripState,
[key]: value,
});
Tell the setState that you want to use the most up-to-date value:
setTripState(currentValue => ({
...currentValue,
[key]: value,
}));