0

I want to pass the item (asset) from a Flastlist and present in a child screen. But when I press the item, the parameter is null. I have to go back and press it again for the parameter to be set. And if I press a different item, the old item still lingers until I press the new item a second time. I don't know if useEffect is the best way to do it. I am just trying different approaches but have not had any luck with useEffect, useFocusEffect, or none.

Parent with the Flastlist

export default function SitesScreen(props) {
const [sites, setSites] = useState(["Power Plant", "Paper Mill", "Plastic Injection"])
const [selectedItem, setSelectedItem] = useState(null)


const Item = ({ item, onPress }) => (
    <TouchableOpacity onPress={onPress} style={[styles.item]} >
        <Text style={styles.text}>{item}</Text>
    </TouchableOpacity>
)

const renderItem = ({ item }) => {
    return (
        <View style={styles.itemContainer} >
            <Item
                item={item}
                onPress={() => onItemSelected(item)}
            />
        </View >
    )
}

const onItemSelected = (item) => {
    setSelectedItem(item)
    props.navigation.navigate("Asset", { asset: selectedItem })
}

return (
    <View style={styles.container}>
        <CustomHeader title="Sites" navigation={props.navigation} isHome={true} ></CustomHeader>
        <View style={styles.contentContainer}>
            <View style={{ width: '90%', height: '50%', alignItems: 'center', bottom: -150 }} >
                <FlatList
                    data={sites}
                    renderItem={renderItem}
                    keyExtractor={(item) => JSON.stringify(item)}
                />
            </View>
        </View>
    </View>
)}

Child screen to present item

export default function SitesScreen(props) {

const [asset, setAsset] = useState('')


useEffect(() => {


    setAsset(props.route.params.asset)
    console.log(asset)

}, [])



return (
    <View style={styles.container}>
        <CustomHeader title="Asset" navigation={props.navigation} isHome={false} ></CustomHeader>
        <View style={styles.contentContainer}>
            <Text style={styles.text} >{asset}</Text>
            <View style={{ width: '90%', height: '50%', alignItems: 'center', bottom: -150 }} >

            </View>
        </View>
    </View>
)}
Jakobk
  • 13
  • 2

2 Answers2

0

When you pass the selectedItem value as a parameter to the next screen, the new state set from setSelectedItem has not been applied to the component yet. Because the new state hasn't been applied, you are still passing the initial null value that was set for selectedItem. This happens because state values are used by functions based on their current closures.

See this StackOverflow post for a more detailed explanation about this problem.

renellc
  • 101
  • 1
  • 6
  • Thanks a lot. I solved it by moving the navigate action to the useEffect hook and letting it check until selectedItem was fulfilled. – Jakobk Aug 19 '21 at 06:54
0

Problem solved.

The parent screen needs to have the navigate action in the useEffect hook, and not in the onItemSelected function. That way it waits until the state has been changed before it navigates.

useEffect(() => {
    if (selectedItem) {
        props.navigation.navigate("Asset", { asset: selectedItem })
    }
}, [selectedItem])
Jakobk
  • 13
  • 2