-2

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.

1

2 Answers 2

1

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]);
Sign up to request clarification or add additional context in comments.

8 Comments

Ok. What can i do for this issue. :(
Updated @likithsai
is it possible to setItemData(itemData) inside the useEffect()?. I know its a silly question, but i actually want to store the value inside a variable.
of course, you can. However in the example provided above you don't need
Just update your onPressItems callback to js (item) => { ToastAndroid.show('item: ' + item, ToastAndroid.LONG) setItemData(item) }
|
0

Your code is working just as expected. One of the hooks that are useful to watch for state updates is useEffect. You can add this to your code and see it's working properly:

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

    React.useEffect(() => {
      console.log('updated itemData:', itemData)
    }, [itemData])

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

You need to take into consideration that useState updates are asynchronous, which means the change won't be reflected immediately.

2 Comments

OK. Can i use setItemData(itemData) inside the useEffect()?
Well, it depends on what you are trying to do. If you dependency array in your useEffect includes itemData it won't make any sense since it will create a loop. What you can do is to show the Toast inside the useEffect to show the correct data.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.