Reputation: 51
I created an accordion and I created some logic for it but when I look at my code it doesn't feel right. I don't know where to ask so I'm asking here.
So I created an accordion component and Implemented it on my screen. What is specific about this accordion is that when one accordion opens other one closes. So I used useState()
that I forward as a prop to the accordion.
I was also thinking to put useState()
inside the accordion but I don't know how to close it when I click on the other accordion. So I created this.
I need tips on how to improve it or how to make it cleaner because right now when I look at the code it works but it doesn't look good.
//AccordionCompontent.js
import React from 'react'
import { StyleSheet, View, Text, Dimensions } from 'react-native';
import Collapsible from 'react-native-collapsible';
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
const Accordion = props => {
return (
<View>
<TouchableWithoutFeedback onPress={props.onPress}>
<View style={styles.accordionContainer}>
<Text style={styles.accordionContainerTitle} >{props.title}</Text>
</View>
</TouchableWithoutFeedback>
<Collapsible style={styles.accordionCollapsedContainer} collapsed={props.isCollapsed}>
{props.accordionRender}
</Collapsible>
</View>
);
}
export default Accordion;
const styles = StyleSheet.create({
accordionContainer: {
justifyContent:'center',
borderBottomWidth: 1,
borderBottomColor: '#fff',
minHeight: Dimensions.get('window').height / 15
},
accordionCollapsedContainer: {
borderBottomWidth: 1,
borderBottomColor: '#fff'
},
accordionContainerTitle: {
color: '#fff',
fontSize: 16,
marginLeft:10
},
})
//InformationScreen.js
import React, { useCallback, useLayoutEffect, useState } from 'react'
import { Text, View, StyleSheet, TouchableWithoutFeedback } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons'
import BodyText from '../components/Atomic/BodyText';
import Accordion from '../components/Accordion/Accordion';
const InformationScreen = props => {
const [isCollapsed, setIsCollapsed] = useState([true, true, true, true, true])
const collapse = (id) => {
let updatetIsCollapsed = [...isCollapsed]
updatetIsCollapsed[id] = !updatetIsCollapsed[id]
const filteredUpdateIsCollapse = updatetIsCollapsed.filter((value, index) => id !== index)
filteredUpdateIsCollapse.forEach(element => {
if (!element) {
const index = filteredUpdateIsCollapse.indexOf(element)
filteredUpdateIsCollapse[index] = true
}
});
filteredUpdateIsCollapse.splice(id, 0, updatetIsCollapsed[id])
setIsCollapsed(filteredUpdateIsCollapse)
}
useLayoutEffect(() => {
props.navigation.setOptions({
title: 'Information',
headerStyle: {
backgroundColor: '#000'
},
headerTitleStyle: {
fontSize: 22,
color: '#fff'
},
headerLeft: () => (
<View></View>
),
headerRight: () => (
<TouchableWithoutFeedback onPress={() => {
props.navigation.popToTop()
}}>
<View style={styles.iconContainer}>
<Icon name="home" size={30} color={'#fff'} />
</View>
</TouchableWithoutFeedback>
)
})
})
return (
<View style={styles.container}>
<Accordion onPress={useCallback(() => {
collapse(0)
},
[isCollapsed, setIsCollapsed],
)} title={"Lorem"} isCollapsed={isCollapsed[0]} accordionRender={
<View style={styles.accordionItemContainer}>
<View style={styles.accordionItemSpacing}>
<BodyText>Lorem Ipsum</BodyText>
<BodyText>Lorem Ipsum</BodyText>
</View>
<View>
<BodyText>Lorem ipsum</BodyText>
<BodyText>Lorem ipsum</BodyText>
</View>
</View>
} />
<Accordion onPress={useCallback(() => {
collapse(1)
},
[isCollapsed, setIsCollapsed],
)} title={"Bla bla"} isCollapsed={isCollapsed[1]} accordionRender={
<View>
<Text>Test</Text>
<Text>Test</Text>
</View>
} />
<Accordion onPress={useCallback(() => {
collapse(2)
},
[isCollapsed, setIsCollapsed],
)} title={"Bla bla"} isCollapsed={isCollapsed[2]} accordionRender={
<View>
<Text>Test</Text>
<Text>Test</Text>
</View>
} />
<Accordion onPress={useCallback(() => {
collapse(3)
},
[isCollapsed, setIsCollapsed],
)} title={"Bla bla"} isCollapsed={isCollapsed[3]} accordionRender={
<View>
<Text>Test</Text>
<Text>Test</Text>
</View>
} />
<Accordion onPress={useCallback(() => {
collapse(4)
},
[isCollapsed, setIsCollapsed],
)} title={"Lorem Ipsum"} isCollapsed={isCollapsed[4]} accordionRender={
<View style={styles.accordionItemContainer}>
<View style={styles.accordionItemSpacing}>
<BodyText>Lorem Ipsum</BodyText>
<BodyText>Lorem Ipsum</BodyText>
</View>
<View>
<BodyText>Lorem ipsum</BodyText>
<BodyText>Lorem ipsum</BodyText>
</View>
</View>
} />
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#000',
flex: 1,
borderTopWidth: 2,
borderTopColor: '#fff'
}
,
iconContainer: {
height: 50,
width: 50,
borderLeftWidth: 2,
borderLeftColor: '#fff',
overflow: 'hidden',
justifyContent: 'center',
alignItems: 'flex-end'
},
accordionContainerTitle: {
color: '#000',
fontSize: 16,
},
accordionItemContainer: {
paddingVertical: 10,
},
accordionItemText: {
color: '#000',
fontSize: 16,
marginHorizontal: 10,
},
accordionItemSpacing: {
marginBottom: 10
}
})
export default InformationScreen;
Upvotes: 3
Views: 2829
Reputation: 51
Okay after the help of Michael Bahl I was able to put some nicer code. His code was good but I did some adjustments to it. Now everything works good and I can put all I need in my accordion.
I had one small change in the accordionCompontent.js and on the screen, I applied the code that Michael showed with some small adjustments to make it more flexible for me.
//AccordionCompontent.js
import React from 'react'
import { StyleSheet, View, Text, Dimensions } from 'react-native';
import Collapsible from 'react-native-collapsible';
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
const Accordion = props => {
return (
<View>
<TouchableWithoutFeedback onPress={props.onPress}>
<View style={styles.accordionContainer}>
<Text style={styles.accordionContainerTitle} >{props.title}</Text>
</View>
</TouchableWithoutFeedback>
<Collapsible style={styles.accordionCollapsedContainer}
//The small change is at collapsed
collapsed={!props.isCollapsed}>
{props.accordionRender}
</Collapsible>
</View>
);
}
export default Accordion;
const styles = StyleSheet.create({
accordionContainer: {
justifyContent:'center',
borderBottomWidth: 1,
borderBottomColor: '#fff',
minHeight: Dimensions.get('window').height / 15
},
accordionCollapsedContainer: {
borderBottomWidth: 1,
borderBottomColor: '#fff'
},
accordionContainerTitle: {
color: '#fff',
fontSize: 16,
marginLeft:10
},
})
import React, { useCallback, useLayoutEffect, useState } from 'react'
import { Text, View, StyleSheet, TouchableWithoutFeedback } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons'
import BodyText from '../components/Atomic/BodyText';
import Accordion from '../components/Accordion/Accordion';
const getAccordionItems = (version, expiresDate, scriptSize, packageSize) => ([
['General Information',
<View>
<View style={styles.accordionItemSpacing}>
<BodyText>Version {version}</BodyText>
<BodyText>License expires on {expiresDate}</BodyText>
</View>
<View>
<BodyText>Size of scripts folder: {scriptSize} MB</BodyText>
<BodyText>Size of packages folder: {packageSize} MB</BodyText>
</View>
</View>],
['lorem',
<View>
<View style={styles.accordionItemSpacing}>
<BodyText>Lorem Ipsum</BodyText>
<BodyText>Lorem Ipsum</BodyText>
</View>
<View>
<BodyText>Lorem ipsum</BodyText>
<BodyText>Lorem ipsum</BodyText>
</View>
</View>],
['lorem',
<View>
<View style={styles.accordionItemSpacing}>
<BodyText>Lorem Ipsum</BodyText>
<BodyText>Lorem Ipsum</BodyText>
</View>
<View>
<BodyText>Lorem ipsum</BodyText>
<BodyText>Lorem ipsum</BodyText>
</View>
</View>],
])
const InformationScreen = props => {
const accordionList = getAccordionItems('1.0', '2021/10/20', 1.00, 0.00)
const [isExpanded, setIsExpanded] = useState();
useLayoutEffect(() => {
props.navigation.setOptions({
title: 'Information',
headerStyle: {
backgroundColor: '#000'
},
headerTitleStyle: {
fontSize: 22,
color: '#fff'
},
headerLeft: () => (
<View></View>
),
headerRight: () => (
<TouchableWithoutFeedback onPress={() => {
props.navigation.popToTop()
}}>
<View style={styles.iconContainer}>
<Icon name="home" size={30} color={'#fff'} />
</View>
</TouchableWithoutFeedback>
)
})
})
accordionList.map((item, index) => {
console.log(item)
console.log(index)
})
return (
<View style={styles.container}>
{accordionList.map((item, index) => (
<Accordion onPress={() => {
if (isExpanded === index){
setIsExpanded(accordionList.size)
} else{
setIsExpanded(index)
}
}} title={item[0]} isCollapsed={isExpanded === index} accordionRender={
<View style={styles.accordionItemContainer}>
{item[1]}
</View>
} />
))}
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#000',
flex: 1,
borderTopWidth: 2,
borderTopColor: '#fff'
}
,
iconContainer: {
height: 50,
width: 50,
borderLeftWidth: 2,
borderLeftColor: '#fff',
overflow: 'hidden',
justifyContent: 'center',
alignItems: 'flex-end'
},
accordionContainerTitle: {
color: '#fff',
fontSize: 16,
},
accordionItemContainer: {
paddingVertical: 10,
},
accordionItemText: {
color:'#fff',
fontSize: 16,
marginHorizontal: 10,
},
accordionItemSpacing: {
marginBottom: 10
}
})
export default InformationScreen;
Upvotes: 1
Reputation: 3659
import React, { useCallback, useLayoutEffect, useState } from 'react'
import { Text, View, StyleSheet, TouchableWithoutFeedback } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons'
import BodyText from '../components/Atomic/BodyText';
import Accordion from '../components/Accordion/Accordion';
const getaccordianItems = () => ([
<View style={styles.accordionItemSpacing}>
<BodyText>Lorem Ipsum</BodyText>
<BodyText>Lorem Ipsum</BodyText>
</View>
<View>
<BodyText>Lorem ipsum</BodyText>
<BodyText>Lorem ipsum</BodyText>
</View>,
<View>
<Text>Test</Text>
<Text>Test</Text>
</View>,
<View>
<Text>Test</Text>
<Text>Test</Text>
</View>,
<View>
<Text>Test</Text>
<Text>Test</Text>
</View>,
<View>
<Text>Test</Text>
<Text>Test</Text>
</View>
])
const InformationScreen = props => {
const [isExpandedIndex, setIsExpanded] = useState();
useLayoutEffect(() => {
props.navigation.setOptions({
title: 'Information',
headerStyle: {
backgroundColor: '#000'
},
headerTitleStyle: {
fontSize: 22,
color: '#fff'
},
headerLeft: () => (
<View></View>
),
headerRight: () => (
<TouchableWithoutFeedback onPress={() => {
props.navigation.popToTop()
}}>
<View style={styles.iconContainer}>
<Icon name="home" size={30} color={'#fff'} />
</View>
</TouchableWithoutFeedback>
)
})
})
return (
<View style={styles.container}>
{accordionList.map((item,index)=>(
<Accordion onPress={()=> { setIsExpanded(index) }} title={"Lorem"} isCollapsed={isExpanded !== index} accordionRender={
<View style={styles.accordionItemContainer}>
{item}
</View>
} />
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#000',
flex: 1,
borderTopWidth: 2,
borderTopColor: '#fff'
}
,
iconContainer: {
height: 50,
width: 50,
borderLeftWidth: 2,
borderLeftColor: '#fff',
overflow: 'hidden',
justifyContent: 'center',
alignItems: 'flex-end'
},
accordionContainerTitle: {
color: '#000',
fontSize: 16,
},
accordionItemContainer: {
paddingVertical: 10,
},
accordionItemText: {
color: '#000',
fontSize: 16,
marginHorizontal: 10,
},
accordionItemSpacing: {
marginBottom: 10
}
})
export default InformationScreen;
Upvotes: 2