I have a Flatlist that renders multiple posts, each post has a text section, the text can get very big so I'm using a show more method to expand/hide the text, and I'm handling the status of it using a state, however, when I click on a post to expand the text, it expands all posts in the Flatlist, I tried creating a dynamic Ref for each post, but I can't figure out a way to change the text content accordingly, anything I'm missing?
here's my code:
const [showMore, setShowMore] = useState(false);
const refs = useRef([]);
// Inside a Flatlist render item:
<View style={styles.postContainer}>
{item.data.postText.length > 120 ? (
showMore ? (
<TouchableOpacity onPress={() => setShowMore(!showMore)}
ref={(expandableText) => (refs.current[index] = expandableText)}>
<Text style={styles.postDescription}>{item.data.postText}</Text>
<Text style={styles.seeMore}>Show less</Text>
</TouchableOpacity>
) : (
<TouchableOpacity onPress={() => setShowMore(!showMore)}>
<Text style={styles.postDescription}>
{`${item.data.postText.slice(0, 120)}... `}
</Text>
<Text style={styles.seeMore}>Show more</Text>
</TouchableOpacity>
)
) : (
<Text style={styles.postDescription}>{item.data.postText}</Text>
)}
</View>
CodePudding user response:
You are using the same state for all items of the FlatList
. Hence, if you change the state, all items will be expanded. You could keep a boolean array as a state. The index of this state array corresponds to the index of a component inside the flatlist.
// data is the data of your FlatList
// we use this to initialize each show more value with false
const [showMore, setShowMore] = useState(data.map(data => false))
In your render function you use it as follows.
renderItem={({item, index}) => {
return <View style={styles.postContainer}>
{item.data.postText.length > 120 ? (
showMore[index] ? (
<TouchableOpacity onPress={() => handleShowMore(index)}
ref={(expandableText) => (refs.current[index] = expandableText)}>
<Text style={styles.postDescription}>{item.data.postText}</Text>
<Text style={styles.seeMore}>Show less</Text>
</TouchableOpacity>
) : (
<TouchableOpacity onPress={() => handleShowMore(index)}>
<Text style={styles.postDescription}>
{`${item.data.postText.slice(0, 120)}... `}
</Text>
<Text style={styles.seeMore}>Show more</Text>
</TouchableOpacity>
)
) : (
<Text style={styles.postDescription}>{item.data.postText}</Text>
)}
</View>
}
The handleShowMore
function is as follows.
function handleShowMore(index) {
setShowMore(prev => prev.map((element, idx) => {
if(idx === index) {
return !element
}
return element
}))
}