I have To-Do list elements which can expand and collapse by pressing the associated button.
By pressing on the EXPAND Button the height of the Animated ScrollView gets adjusted. From 0 to 100 when expanding and from 100 to 0 when collapsing. When we expand two list-objects at the same time, the screen begins to flicker.
Here the code of one single todo-element (it is abbreviated, means the DONE button is not in it):
import React, { useState, useRef, memo } from 'react';
import { Animated, Text, View, Button, ScrollView } from 'react-native';
import longText from '../data/data';
const ListObject = (props) => {
//Object Expand and Collapse feature
const expandValue = useRef(new Animated.Value(0)).current;
const [expandState, setExpand] = useState(false);
const expandAnimation = () => {
Animated.timing(expandValue, {toValue: 100, duration: 1000, useNativeDriver: false}).start();
setExpand(true);
}
const collapseAnimation = () => {
Animated.timing(expandValue, {toValue: 0, duration: 1000, useNativeDriver: false}).start();
setExpand(false);
}
return (
<View style={{ margin: props.margin }}>
<View style={{
flexDirection: 'row',
backgroundColor: 'grey',
borderRadius: 10,
}}>
<Button title='EXPAND' style={{
flex: 1,
backgroundColor: 'blue',
}}
onPress={ expandState ? collapseAnimation : expandAnimation }
/>
</View>
<Animated.ScrollView style={{
flex: 1,
paddingHorizontal: 40,
backgroundColor: 'grey',
borderRadius: 10,
maxHeight: expandValue
}}>
<Text>{ props.text }</Text>
</Animated.ScrollView>
</View>
);
}
export default memo(ListObject);
Here is the code for the App. To make a collection of all todo-elements, I map over a list and assign a key to each element:
mport React, { useRef, useState } from 'react';
import { Animated, StyleSheet, ScrollView, Text, View, SafeAreaView, Button } from 'react-native';
import longText from './src/data/data';
import ListObject from './src/components/list-object'
const styles = StyleSheet.create({
safeContainer: {
flex: 1.2
},
headerContainer: {
flex: 0.2,
flexDirection: 'column',
justifyContent: 'center',
backgroundColor: 'lightblue',
},
headerFont: {
fontSize: 50,
textAlign: 'center',
},
scrollContainer: {
flex: 1
}
});
const App = () => {
const numbers = [1,2,3,4,5,6,7,8,9];
const listItems = numbers.map((number) =>
<ListObject key={number.toString()} margin={10} headerText='I am the header of the to-do element' text={longText} />
)
return (
<SafeAreaView style={ styles.safeContainer } >
<View style={ styles.headerContainer }>
<Text style={ [styles.headerFont] }>LIST MAKER</Text>
</View>
<ScrollView style={ styles.scrollContainer }>
{listItems}
</ScrollView>
</SafeAreaView>
);
};
export default App;
I expected no flickering. The flickering appears also on my physical Android device. I have searched for similar problems and checked other libraries how they implement it.
2
Answers
I found the mistake by myself, it's a beginner's mistake.
Instead of managing the state of the component in the component itself, I had to lift the state up to the parent.
Here the link to the ReactJS learning doc.
For this, you can use react-native-collapsible
For better performance and a smooth experience use this one.