React Native class component accordion into functional component - reactjs

The following code displays an accordion but I need to make use of useContext which I understand only works with functional components and I'm having a hard time understand how to convert it into a functional component.
class AnnualFeeScreen extends Component {
state = {
activeSections: [],
};
_renderHeader(section, index, isActive) {
let meanValStatus = '#39D0B5';
if (section.meanDiffVal >= 1.05) {
meanValStatus = '#FCD561';
} else if (section.meanDiffVal < 0.95) {
meanValStatus = '#bbb';
}
return (
<View style={styles.flexRow}>
<View style={{flex:2}}>
<Text style={styles.h6}>{!isActive ? '+' : '-'} {section.title}</Text>
</View>
<View style={styles.flex}>
<Text style={[styles.h6, {textAlign: 'right'}]}>{Math.round((section.titleValue) / 12, 0)} kr/mån</Text>
</View>
<View style={[styles.circleStatus, {backgroundColor: meanValStatus}]}></View>
</View>
);
};
_renderContent = section => {
return (
<View>
{section.content.map((item, key) =>
<View style={styles.accordionContent} key={key}>
<View style={styles.flexRow}>
<View style={{flex: 2}}>
<Text style={[styles.p, {fontWeight: 'normal'}]}>{item.title}</Text>
</View>
<View style={styles.flex}>
<Text style={[styles.p, {fontWeight: 'normal', textAlign: 'right'}]}>{Math.round((item.value * aptPercentage) / 12, 0)} kr/mån</Text>
</View>
</View>
</View>
)}
</View>
);
};
_updateSections = activeSections => {
this.setState({ activeSections });
};
render () {
return (
<ScrollView style={styles.backgroundPrimary} showsVerticalScrollIndicator='false'>
<View style={styles.backgroundSecondary}>
<View style={styles.container}>
<Accordion
sections={brfCostRows}
activeSections={this.state.activeSections}
renderHeader={this._renderHeader}
renderContent={this._renderContent}
onChange={this._updateSections}
sectionContainerStyle={styles.accordion}
underlayColor='transparent'
/>
</View>
</View>
</ScrollView>
);
};
};
To fetch data with axios I use the following in other screens but it's not working with the class component:
const { state, fetchUser } = useContext(UserContext);
And in the view:
<NavigationEvents onWillFocus={fetchUser} />
I've tried to remove the render part change the first part to the following but it's complaining about the first function _renderHeader (Unexpected token):
const AnnualFeeScreen = () => {

First of all while converting, class component to functional component with hooks, you must note that, there won't be a this variable inside functional component. Secondly the state inside a functional component would need to be implemented using useState hook
const AnnualFeeScreen () => {
const [activeSections, setActiveSections] = useState([]);
const _renderHeader(section, index, isActive) {
let meanValStatus = '#39D0B5';
if (section.meanDiffVal >= 1.05) {
meanValStatus = '#FCD561';
} else if (section.meanDiffVal < 0.95) {
meanValStatus = '#bbb';
}
return (
<View style={styles.flexRow}>
<View style={{flex:2}}>
<Text style={styles.h6}>{!isActive ? '+' : '-'} {section.title}</Text>
</View>
<View style={styles.flex}>
<Text style={[styles.h6, {textAlign: 'right'}]}>{Math.round((section.titleValue) / 12, 0)} kr/mån</Text>
</View>
<View style={[styles.circleStatus, {backgroundColor: meanValStatus}]}></View>
</View>
);
};
const _renderContent = section => {
return (
<View>
{section.content.map((item, key) =>
<View style={styles.accordionContent} key={key}>
<View style={styles.flexRow}>
<View style={{flex: 2}}>
<Text style={[styles.p, {fontWeight: 'normal'}]}>{item.title}</Text>
</View>
<View style={styles.flex}>
<Text style={[styles.p, {fontWeight: 'normal', textAlign: 'right'}]}>{Math.round((item.value * aptPercentage) / 12, 0)} kr/mån</Text>
</View>
</View>
</View>
)}
</View>
);
};
const _updateSections = activeSections => {
setActiveSections(activeSections);
};
return (
<ScrollView style={styles.backgroundPrimary} showsVerticalScrollIndicator='false'>
<View style={styles.backgroundSecondary}>
<View style={styles.container}>
<Accordion
sections={brfCostRows}
activeSections={activeSections}
renderHeader={_renderHeader}
renderContent={_renderContent}
onChange={_updateSections}
sectionContainerStyle={styles.accordion}
underlayColor='transparent'
/>
</View>
</View>
</ScrollView>
);
};

Related

Show button when 2 inputs are full and valid in react native

****I have a react native page app with 2 inputs. ****
I want to show the "submit" button once all of the 2 fields have a value.
(button is invisible until the 2 input fields have value)
this is my page code :
class Page3 extends Component {
render() {
const {navigate} = this.props.navigation;
return (
<View style={styles.container}>
<View style={styles.question1Stack}>
<Text style={styles.question1}>Question1</Text>
<ImageBackground
source={require("./assets/undraw_Friends_online_re_r7pq.png")}
resizeMode="contain"
style={styles.image}
imageStyle={styles.image_imageStyle}
>
<TouchableOpacity onPress={() =>{this.props.navigation.navigate('Page2')}}>
<Icon name="chevron-left" style={styles.icon1}></Icon>
</TouchableOpacity>
</ImageBackground>
</View>
<TouchableOpacity
title="submit"
onPress={() => {
this.props.navigation.navigate('Page4');
}}>
<Text style={styles.next}>
Next
</Text>
</TouchableOpacity>
<MaterialHelperTextBox
style={styles.materialHelperTextBox}
></MaterialHelperTextBox>
<MaterialHelperTextBox1
style={styles.materialHelperTextBox1}
></MaterialHelperTextBox1>
</View>
);
}
}
these are my input fields :
<MaterialHelperTextBox
style={styles.materialHelperTextBox}
></MaterialHelperTextBox>
<MaterialHelperTextBox1
style={styles.materialHelperTextBox1}
></MaterialHelperTextBox1>
you most define to two state for two TextInput , than set TextInput value in onChangeText check value is not null and valid , set true states for check, I don't know you use MaterialHelperTextBox1 by witch component but code maybe like this:
class Page3 extends Component {
constructor(props) {
super(props);
this.state = {
checkInput1:false,
checkInput2:false,
inputValue1:'',
inputValue2:'',
};
};
render() {
const {navigate} = this.props.navigation;
return (
<View style={styles.container}>
<View style={styles.question1Stack}>
<Text style={styles.question1}>Question1</Text>
<ImageBackground
source={require("./assets/undraw_Friends_online_re_r7pq.png")}
resizeMode="contain"
style={styles.image}
imageStyle={styles.image_imageStyle}
>
{checkInput1 && checkInput2 ?
<TouchableOpacity onPress={() =>
{this.props.navigation.navigate('Page2')}}>
<Icon name="chevron-left" style={styles.icon1}></Icon>
</TouchableOpacity>
:
null
}
</ImageBackground>
</View>
<TouchableOpacity
title="submit"
onPress={() => {
this.props.navigation.navigate('Page4');
}}>
<Text style={styles.next}>
Next
</Text>
</TouchableOpacity>
<MaterialHelperTextBox
style={styles.materialHelperTextBox}
onChangeText={value => {this.setstate({inputValue1:value});
_checkInputIsValid1();}}
defaultValue={this.state.inputValue1}
></MaterialHelperTextBox>
<MaterialHelperTextBox1
style={styles.materialHelperTextBox1}
onChangeText={value => {this.setstate({inputValue2:value});
_checkInputIsValid2();}}
defaultValue={this.state.inputValue1}
></MaterialHelperTextBox1>
</View>
);
}
}
_checkInputIsValid1(){
//check your rules for input1 there if true set state checkInput1 as true
}
_checkInputIsValid2(){
//check your rules for input2 there if true set state checkInput2 as true
}

How to pass Parent Flatlist's Index value to Child Flatlist's onPress function?

How to pass parent Flatlist's index value to child Flatlist's function so I can use it in function and change value by setState.
So how to pass parent Flatlist's index value to child Flatlist's function so I can use it in function and change value by setState.
It starts with a list that built-in state
constructor(props) {
super(props);
this.state = {
list: [
{
question: 'il veicolo ha la gomma forata?',
answers: [
{
radioButtonValue: false,
text: strings.CONFIRMVIEW_yes,
},
{
radioButtonValue: true,
text: strings.CONFIRMVIEW_no,
},
],
},
]
}
}
checkBoxSelection = (item, index) => {
// if (item.radioButtonValue == index) {
// this.list.answers[index].radioButtonValue = true
// }
console.log(this.state.list[0].answers[index].radioButtonValue)
}
_renderItem = ({ item, index }) => {
return (
<View style={styles.cellView}>
<Text style={styles.questionText}>
{item.question.toUpperCase()}
</Text>
<FlatList
data={item.answers}
horizontal={true}
showsHorizontalScrollIndicator={true}
scrollEnabled={true}
bounces={false}
renderItem={this._renderItemOptions}
/>
{/* <View style={styles.yesNoRadioButtonView}>
<View style={styles.yesChekboxView}>
<TouchableOpacity onPress={ () => {console.log("TEST1"); this.checkBoxSelection()} }>
<Image source={(item.answers == index) ? AppImages.radioOn : AppImages.radioOff} style={styles.radioButton} />
</TouchableOpacity>
<Text style={styles.yesNoText}>
{strings.CONFIRMVIEW_yes}
</Text>
</View>
<View style={styles.noRadioButtonView}>
<TouchableOpacity onPress={() => { this.checkBoxSelection.bind(this) }}>
<Image source={(item.answers == 0) ? AppImages.radioOn : AppImages.radioOff} style={styles.radioButton} />
</TouchableOpacity>
<Text style={styles.yesNoText}>
{strings.CONFIRMVIEW_no}
</Text>
</View>
</View> */}
</View>
)
}
_renderItemOptions = ({ item, index }) => {
return (
<View>
<View style={styles.yesNoRadioButtonView}>
<TouchableOpacity onPress={() => { this.checkBoxSelection(item, index) }}>
<View style={styles.yesChekboxView}>
<Image
source={item.radioButtonValue ? AppImages.radioOn : AppImages.radioOff}
style={styles.radioButton}
/>
<Text style={styles.yesNoText}>
{item.text}
</Text>
</View>
</TouchableOpacity>
</View>
</View>
)
}
render() {
return (
<Container>
<Content style={styles.container}>
<FlatList
data={this.state.list}
showsVerticalScrollIndicator={false}
scrollEnabled={false}
bounces={false}
renderItem={this._renderItem}
/>
</Content>
<SafeAreaView>
<TouchableOpacity
style={[LayoutStyle.appBtn1]}
>
<Text style={[LayoutStyle.appBtnText1]}>
{strings.DAMAGE_SURVEY_comeOn.toUpperCase()}
</Text>
</TouchableOpacity>
</SafeAreaView>
</Container>
)
}
In Parent Flatlist's renderItem function
replace
renderItem = { () => {this.renderItemOptions(item, index)}}
with
renderItem={(childData) => this._renderItemOptions(childData, index)}
and then in child Flatlist's renderItemOption function need to get parentIndex with another name.
_renderItemOptions = ({ item, index }, parentIndex) => {
console.log("hello")
return (
<View>
<View style={styles.yesNoRadioButtonView}>
<TouchableOpacity onPress={() => { this.checkBoxSelection(item, index, parentIndex) }}>
<View style={styles.yesChekboxView}>
<Image
source={item.radioButtonValue ? AppImages.radioOn : AppImages.radioOff}
style={styles.radioButton}
/>
<Text style={styles.yesNoText}>
{item.text}
</Text>
</View>
</TouchableOpacity>
</View>
</View>
)
}
Try updating your renderItem prop in your FlatList to explicitly pass the index
renderItem={({item, index}) => this._renderItemOptions(item, index)}

React Native child component not rendering on onPress event

I am trying to render the child component on onPressevent, the console.log works fine but components in the return function doesn't works.
Parent component:
onPress = (img,title,content) => {
this.setState({
show:true,
img:img,
title:title,
content:content
})
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={({item}) => (
<TouchableOpacity
onPress={() => this.onPress(item.urlToImage,item.title,item.content)}
>
<View style={styles.picsCont}>
<Image style={styles.pics} source={{uri: item.urlToImage}}/>
<Text style={{color:'white', fontSize: 15, fontWeight: '700', paddingTop:10}}>
{item.title}
</Text>
</View>
</TouchableOpacity>
)}
keyExtractor={item => item.title}
/>
{this.state.show ?
<NewsView
img={this.state.img}
title={this.state.title}
content={this.state.content}
/> :
null
}
</View>
);
}
}
Child Component:
export default class NewsView extends Component {
render() {
console.log(this.props.img)
return (
<View style={styles.container}>
<Image style={styles.picsCont} source={{uri:this.props.img}} />
<Text style={styles.news}>{this.props.title}</Text>
<Text style={styles.news}>{this.props.content}</Text>
</View>
)
}
}
Thanks for the help...!
It might be the styles. If your child component has position:'absolute', it´s probably under your parent component, you can try to put on your child component view zIndex:10

React Native Expandable View Issue

This is my component usage
<Panel title="ABC Trade & Investments (Pvt) LTd" amount="$,350.00 LKR">
<View style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<TextInput style={styles.textBox} />
</View>
<View style={styles.container}>
<TouchableHighlight
style={styles.buttonContainerOK}
onPress={this.onPressLearnMore}
underlayColor="#a7ccaf"
>
<Image
style={styles.buttonImage}
source={require("./assets/img/ic_done_24px.png")}
/>
</TouchableHighlight>
<View style={styles.space} />
<TouchableHighlight
style={styles.buttonContainerDelete}
onPress={this.onPressLearnMore}
underlayColor="#f79191"
>
<Image
style={styles.buttonImage}
source={require("./assets/img/ic_clear_24px.png")}
/>
</TouchableHighlight>
</View>
</View>
</Panel>
Here I add my component code
class Panel extends Component {
constructor(props) {
super(props);
this.icons = {
up: require("../assets/img/Arrowhead-01-128.png"),
down: require("../assets/img/Arrowhead-Down-01-128.png")
};
this.state = {
title: props.title,
expanded: false,
animation: new Animated.Value()
};
}
onPressLearnMore() {
console.log("Test");
}
componentWillMount() {
console.log("this.state.expanded => " + this.state.expanded);
console.log("this.state.maxHeight => " + this.state.maxHeight);
console.log("this.state.minHeight => " + this.state.minHeight);
}
toggle() {
let initialValue = this.state.expanded
? this.state.maxHeight + this.state.minHeight
: this.state.minHeight,
finalValue = this.state.expanded
? this.state.minHeight
: this.state.maxHeight + this.state.minHeight;
this.setState({
expanded: !this.state.expanded
});
console.log("initialValue => " + initialValue);
this.state.animation.setValue(initialValue);
Animated.spring(this.state.animation, {
toValue: finalValue
}).start();
console.log("finalValue => " + finalValue);
}
_setMaxHeight(event) {
if (!this.state.maxHeight) {
console.log("_setMaxHeight => " + event.nativeEvent.layout.height);
this.setState({
maxHeight: event.nativeEvent.layout.height
});
}
}
_setMinHeight(event) {
if (!this.state.minHeight) {
console.log("_setMinHeight ! => " + event.nativeEvent.layout.height);
this.setState({
minHeight: event.nativeEvent.layout.height,
animation: new Animated.Value(event.nativeEvent.layout.height)
});
}
}
render() {
let icon = this.icons["down"];
if (this.state.expanded) {
icon = this.icons["up"];
}
return (
<Animated.View
style={[styles.container, { height: this.state.animation }]}
>
<View
style={styles.titleContainer}
onLayout={this._setMinHeight.bind(this)}
>
<View style={styles.header}>
<Text style={styles.title}>{this.state.title}</Text>
<Text style={styles.amount}>4,350.00 LKR</Text>
</View>
<TouchableHighlight
style={styles.toggle_button}
onPress={this.toggle.bind(this)}
underlayColor="#f1f1f1"
>
<Image style={styles.buttonImage} source={icon} />
</TouchableHighlight>
<TouchableHighlight
style={styles.approve_button}
onPress={this.onPressLearnMore}
underlayColor="#a7ccaf"
>
<Image
style={styles.listButtonImage}
source={require("../assets/img/ic_done_24px.png")}
/>
</TouchableHighlight>
<View style={styles.space} />
<TouchableHighlight
style={styles.reject_button}
onPress={this.onPressLearnMore}
underlayColor="#f79191"
>
<Image
style={styles.listButtonImage}
source={require("../assets/img/ic_clear_24px.png")}
/>
</TouchableHighlight>
</View>
<View style={styles.body} onLayout={this._setMaxHeight.bind(this)}>
{this.props.children}
</View>
</Animated.View>
);
}
}
Issue is that I have added TextInput to expanded Panel.But once I clicked it my view is collapsed.here I will attached image of my two scenarios.
It seems issue occur due to onLayout={this._setMaxHeight.bind(this)} this code.But I could not resolve that.Please help me.
FYI - this is the link I refer to build this - https://moduscreate.com/blog/expanding-and-collapsing-elements-using-animations-in-react-native/
It seems that, nested event bubbling took place here. You can avoid this by adding onFocus and onKeyPress events to yout TextInput and need to handle parent event as follows:
<TextInput
onFocus={this.restrictParentClick.bind(this)}
onKeyPress={this.restrictParentClick.bind(this)}
/>
And this will be your restrictParentClick function as follows:
restrictParentClick (evnt) {
evnt.preventDefault()
evnt.stopPropagation();
if(evnt.nativeEvent)
evnt.nativeEvent.stopImmediatePropagation();
}
}

How to do the multi Button onPress functions in one common component - React native

I have a component call ButtonLayout.js
export const ButtonLayout = () => {
return (
<View style={styles.row}>
<TouchableOpacity >
<Text>Book Now</Text>
</TouchableOpacity>
<TouchableOpacity >
<Text>Schedule</Text>
</TouchableOpacity>
</View>
)
}
and i have import this component to another common component called mapComponent and it look like following.
return (
<View style={styles.container}>
<MapView
provider={MapView.PROVIDER_GOOGLE}
style={styles.map}
region={this.props.region}
>
<MapView.Marker
coordinate={this.props.region}
pinColor='green'
/>
</MapView>
<ButtonLayout style={{ marginBottom: 5 }} />
</View>
);
so my question is how can i handle the onPress() function of the buttons in ButtonLayout.js from index.js ?
Make your ButtonLayout component accept callback props, like so:
export const ButtonLayout = ({onBook, onSchedule}) => (
<View style={styles.row}>
<TouchableOpacity onPress={onBook}>
<Text>Book Now</Text>
</TouchableOpacity>
<TouchableOpacity onPress={onSchedule}>
<Text>Schedule</Text>
</TouchableOpacity>
</View>);
Then, pass the callbacs in the parent component’s render function as props
<ButtonLayout onBook={…} onSchedule={…} />
Don’t forget to bind the context to the callbacks
In your button Buttonlayout.js define like this:
<TouchableOpacity onPress={() => this.props.onPress()}>
<Text>Book Now</Text>
</TouchableOpacity>
And define onPress function on each file you use this component just like.
<ButtonLayout style={{ marginBottom: 5 }} onPress={() => {'your logic..'}}/>
Define your callback variables in ButtonLayout and add them to your touchables.
export const ButtonLayout = ({ onBookPress, onSchedulePress }) => {
return (
<View style={styles.row}>
<TouchableOpacity onPress={onBookPress}>
<Text>Book Now</Text>
</TouchableOpacity>
<TouchableOpacity onPress={onSchedulePress} >
<Text>Schedule</Text>
</TouchableOpacity>
</View>
)
}
Define your callbacks in index:
indexOnBookPress = () => {
...do something
}
indexOnSchedulePress = () => {
...do something
}
return (
<View style={styles.container}>
<MapView
provider={MapView.PROVIDER_GOOGLE}
style={styles.map}
region={this.props.region}
>
<MapView.Marker
coordinate={this.props.region}
pinColor='green'
/>
</MapView>
<ButtonLayout style={{ marginBottom: 5 }} onBookPress={this.indexOnBookPress} onSchedulePress={this.indexOnSchedulePress} />
</View>
);

Resources