The Goal:
My React Native App shows a list of <Button />
based on the value from a list of Object someData
. Once a user press a <Button />
, the App should shows the the text
that is associated with this <Button />
. I am trying to achieve this using conditional rendering.
The Action:
So first, I use useEffect
to load a list of Boolean
to showItems
. showItems
and someData
will have the same index so I can easily indicate whether a particular text
associated with <Button />
should be displayed on the App using the index
.
The Error:
The conditional rendering does not reflect the latest state
of showItems
.
The Code:
Here is my code example
import {someData} from '../data/data.js';
const App = () => {
const [showItems, setShowItems] = useState([]);
useEffect(() => {
const arr = [];
someData.map(obj => {
arr.push(false);
});
setShowItems(arr);
}, []);
const handlePressed = index => {
showItems[index] = true;
setShowItems(showItems);
//The list is changed.
//but the conditional rendering does not show the latest state
console.log(showItems);
};
return (
<View>
{someData.map((obj, index) => {
return (
<>
<Button
title={obj.title}
onPress={() => {
handlePressed(index);
}}
/>
{showItems[index] && <Text>{obj.item}</Text>}
</>
);
})}
</View>
);
};
showItems[index] = true;
setShowItems(showItems);
React is designed with the assumption that state is immutable. When you call setShowItems, react does a ===
between the old state and the new, and sees that they are the same array. Therefore, it concludes that nothing has changed, and it does not rerender.
Instead of mutating the existing array, you need to make a new array:
const handlePressed = index => {
setShowItems(prev => {
const newState = [...prev];
newState[index] = true;
return newState;
});
}