react-nativereact-android

React Native: Variable state not updated on first click


I am new in react-native and i am working on an app.

The below code is a simple react-native app which has a custom component with custom events.

But the problem is the variable state is not updated on the first click on the component. But when i click on the second item, The state of the variable is updated.

Please find the code and screenshot below.

App.js

import React, {useState} from 'react';
import { Text, SafeAreaView, ToastAndroid } from 'react-native';
import Dropdown from './components/dropdown';

const app = () => {
    const [ itemData, setItemData ] = useState('');

    return (
        <SafeAreaView style={{ margin: 50 }}>
            <Dropdown 
              onPressItems={(item) => {
                  ToastAndroid.show('item: ' + item, ToastAndroid.LONG)
                  setItemData(item)
                  ToastAndroid.show('setItem: ' + itemData, ToastAndroid.LONG)
              }}/>
        </SafeAreaView>
    );
}

export default app;

Dropdown.js

import React, { useState } from 'react';
import { TouchableOpacity, Text } from 'react-native';

const Dropdown = (props) => {
    return (
        <TouchableOpacity onPress={() => { props.onPressItems('this is sample data') }}>
            <Text>Sample Text</Text>
        </TouchableOpacity>
    );
} 

export default Dropdown;

Screenshot enter image description here

Code: https://snack.expo.dev/@likithsai/custom-component

Please help me on this issue. Thanks.


Solution

  • useState() hook changes the state asynchronously. so you can't make sure that the state will be changed immediately after calling setItemData() function.

    Try useEffect to run a side effect whenever the state changes.

    useEffect(() => {
      ToastAndroid.show("setItem: " + itemData, ToastAndroid.LONG);
    }, [itemData]);
    

    However, this code will show the toast on the component mount. to prevent it try something like this:

    const isInitialMount = useRef(true);
    
    useEffect(() => {
      if (isInitialMount.current) {
        isInitialMount.current = false;
      } else {
        ToastAndroid.show("setItem: " + itemData, ToastAndroid.LONG);
      }
    }, [itemData]);