Home > database >  Why does my useState value reset in onPress method?
Why does my useState value reset in onPress method?

Time:05-02

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,
}));
  • Related