How to handle a touch gesture by multiple components in react native? - react-native

Using React Native 0.47 and yarn, I'm creating an introduction section in which you can swipe through multiple pages and finally get to the home page.
So we swipe pages from right to left and move like this: Slide1 -> Slide2 -> Slide3 -> Slide4 -> Home . I have a component that displays a slide page which covers all of the screen. For example, first slide looks like this:
And the code for that is :
class IntroSlide extends Component {
render () {
return (
<View style={[styles.introSlide, this.props.myStyle]}>
<View style={styles.introSlideIconView}>
<Icon name={this.props.iconName} size={SLIDE_ICON_SIZE} color="white"/>
</View>
<View style={styles.introSlideTextView}>
<Text style={styles.introSlideTextHeader}> {this.props.headerText} </Text>
<Text style={styles.introSlideText}> {this.props.text} </Text>
</View>
</View>
);
}
}
And i use it that here:
import AppIntro from 'react-native-app-intro';
// Other imports here
export default class Intro extends Component {
render() {
return (
<View style={{flex: 1}}>
<AppIntro
showSkipButton={false}
nextBtnLabel={<Text style={styles.introButton}>بعدی</Text>}
doneBtnLabel={<Text style={styles.introButton}>شروع</Text>}
>
<IntroSlide
iconName="user"
myStyle={styles.introSlide1}
headerText="DontCare"
text= "SomeTextDoesntMatter"
/>
</AppIntro>
</View>
);
}
}
I'm using react-native-app-intro for this which provides me a very cool swiper but here's the problem:
I have a small View component with an Icon (react-native-vector-icons) in it as you can see that i want to rotate as i swipe to the next page. I created a panResponder in IntroSlide and set it to top View of it. but my slide can't receive any events. i think some parent views provided by react-native-app-intro captures all the events and i can still swipe through pages but no console log appears. here's what i did:
class IntroSlide extends Component {
constructor(props) {
super(props);
const panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: () => console.log("Moving"),
});
this.pan = panResponder;
}
render () {
return (
<View
style={[styles.introSlide, this.props.myStyle]}
{...this.pan.panHandlers}
>
<View style={styles.introSlideIconView}>
<Icon name={this.props.iconName} size={SLIDE_ICON_SIZE} color="white"/>
</View>
<View style={styles.introSlideTextView}>
<Text style={styles.introSlideTextHeader}> {this.props.headerText} </Text>
<Text style={styles.introSlideText}> {this.props.text} </Text>
</View>
</View>
);
}
}
I did the same to the View component with flex: 1 and i had different result. i get console logs as expected but i can't swipe anymore. So how can i swipe through pages while receiving touch events in parent component ? (In other words, i want two different components to receive touch events, and I'm developing for android)

Related

componentWillMount doesn't get called again when navigating back to my original component

screen A: calling componentWillMount successfully and then navigating to screen B,
screen B: do some redux changes (that will affect the data in WillMount) and then navigating back to A but componentWillMount doesn't get called and preventing desirable data from appearing on the screen
screen A:
componentWillMount(){
this.props.fetchData();
console.log('fetched')
}
renderItem({item}){
return <Text>{item.name}</Text>
}
render(){
const array = Object.values(this.props.data)
return(
<View style={{flex: 1}}>
<Inline>
<View style={styles.container}>
<View style={styles.headerContainer}>
<Header style={styles.header} HeaderText={'EmployeeList'}
/>
</View>
<TouchableOpacity style={styles.buttonContainer}
onPress={()=> this.props.navigation.navigate('CreateEmp')}
//screen B
>
<Text style={styles.buttonStyle}>Add an Employee</Text>
</TouchableOpacity>
</View>
</Inline>
<FlatList
data={array}
renderItem={this.renderItem}
keyExtractor={array1 => array1.name}
/>
</View>
screen B:
functionOne(){
const {name, phone, createEmployee, shift} = this.props
createEmployee(name, phone, shift)
}
functionTwo(){
this.props.navigation.navigate('EmployeeList')//screen A
}
functionCombined(){
this.functionOne();
this.functionTwo();
}
and calling functionCombined in the class of course
The componentWillMount is executed when the screen is rendered.
However, when navigating to the Navigate command, if the screen is first moved, it is rendered to draw the screen, but if it is already rendered, it is not rendered again.
The function shall be moved using a push commands to run again.
functionTwo(){
this.props.navigation.push('EmployeeList')//screen A
}

Create a reusable React Native Modal Component

I'm going back to basics with React Native, as I feel overwhelmed. I have been looking for an implementation of a reusable modal component. I'm looking for examples of a reusable Modal component in RN? Thanks in advance
You can find many examples of this on StackOverflow. Still, if you need example I can help you with one example. You have mentioned modal component in your question, right?
Your component will look like this with props. let the name be ModalComponent for this file.
render() {
const { isVisible, message, textValue } = this.props;
return (
<Modal
animationType="slide"
transparent={false}
isVisible={isVisible}
backdropColor={"white"}
style={{ margin: 0 }}
onModalHide={() => {}}>
<View>
<Text>textValue</Text>
<Text>message</Text>
</View>
</Modal>
);
}
so now in your js file you need to import this modalComponent and after that, you need to write as
<ModalComponent
isVisible={true}
textValue={'hi there'}
message={'trying to make a basic component modal'}/>
Hope this will help for you
EDIT:
Create seperate components that you want to render inside modal. for Ex: component1.js, component2.js, component3.js with props
component1.js:
render(){
const { textVal, message } = this.props
return (
<View>
<Text>{textVal}</Text>
<Text>{message}</Text>
</View>
)
}
now in ModalComponent
render() {
const { first, second, third, isVisible, component1Text, component1Message } = this.props;
<Modal
animationType="slide"
transparent={false}
isVisible={isVisible}
backdropColor={"white"}
style={{ margin: 0 }}
onModalHide={() => {}}>
<View>
{first && <component1
textValue= component1Text
message= component1Message />}
{second && <Component2 />}
{third && <Component2 />}
</View>
</Modal>
In this way, you can achieve it within the single modal.
You will make a component like this giving the parent component all the liberty to change it through props.
render() {
const { isVisible, message, textValue, animationType, backDropColor, style, onModalHide, children } = this.props;
return (
<Modal
animationType= {animationType || 'slide'}
transparent={transparent || false}
isVisible={isVisible || false}
backdropColor={backdropColor || "white"}
style={[modalStyle, style]}
onModalHide={onModalHide}>
{children}
</Modal>
);
}
Then in your parent component, you need to import this component like this:
import ModalComponent from '../ModalComponent'; //path to your component
<ModalComponent isVisible={true}>
<View>
//any view you want to be rendered in the modal
</View>
</ModalComponent>
I had a lot of troubles using react-native modal, sometimes i started the app and could not close it even when i set the isVisible prop to false, it is even worst on IOs, i did a research and these packages are not being maintained properly.
You will save a lot of time by using a top-level navigator like is recommended in the modal docs: https://facebook.github.io/react-native/docs/modal.
I tried https://github.com/react-native-community/react-native-modal but had the same problems because its an extension of the original react-native modal.
I suggest you to use the react-navigation modal as described here: https://reactnavigation.org/docs/en/modal.html#docsNav
You can refer the following code to write Modal component once and use multiple times.
Write once:
import React, { Component } from 'react';
import { View, Text, Button, Modal, ScrollView, } from 'react-native';
export class MyOwnModal extends Component {
constructor(props) {
super(props);
this.state = {
}
render() {
return(
<Modal
key={this.props.modalKey}
transparent={this.props.istransparent !== undefined ? true : false}
visible={this.props.visible}
onRequestClose={this.props.onRequestClose}>
<View style={{
//your styles for modal here. Example:
marginHorizontal: width(10), marginVertical: '30%',
height: '40%', borderColor: 'rgba(0,0,0,0.38)', padding: 5,
alignItems: 'center',
backgroundColor: '#fff', elevation: 5, shadowRadius: 20, shadowOffset: { width: 3, height: 3 }
}}>
<ScrollView contentContainerStyle={{ flex: 1 }}>
{this.props.children}
</ScrollView>
</View>
</Modal>
);
}
}
Now,
You can call your Modal like following example: (By doing this, you avoid re-writing the Modal and its outer styles everytime!)
Example
<MyOwnModal modalKey={"01"} visible={true} onRequestClose={() =>
this.anyFunction()} istransparent = {true}>
<View>
// create your own view here!
</View>
</MyOwnModal>
Note: If you are in using different files don't forget to import , and also you can pass the styles as props.
(You can create/customise props too based on your requirement)
Hope this saves your time.
Happy coding!
I am a contributor of react-native-use-modal.
This is an example of creating a reusable modal in a general way and using react-native-use-modal: https://github.com/zeallat/creating-reusable-react-native-alert-modal-examples
With react-native-use-modal, you can make reusable modal more easily.
This is a comparison article with the general method: https://zeallat94.medium.com/creating-a-reusable-reactnative-alert-modal-db5cbe7e5c2b

How can i change the FlatList item background color when button is pressed in React Native

Let's suppose that i've a FlatList with some items, i press into one of them, then opens me another screen with the details of that item. Alright, so what i need is, after pressing the button called "Got it!" and goes into the back screen(FlatList screen), how can i set the background color to green in the row selected?
So i click in one item of the FlatList, then it shows me another screen with the details of that item
Once im in the Details screen, i press the button "Got it!", and it brings me back to the FlatList screen
This is exactly what i need, set a background color only in the View shown in that item, if i press another item and do the same thing, it will be shown changed the background both of them, and so on...
NOTE: class Details and ProfileActivity are inside App.js as a childs.
class ProfileActivity extends Component
{
GetFlatListItem (Description, Tutorial, Imagen, Title) {
Alert.alert(Description);
this.props.navigation.navigate('Fourth', {Tutorial, Imagen, Title});
}
return(
<View style = { styles.MainContainer }>
<Button title="Logout" onPress={ () => goBack(null) } />
<Text style = {styles.TextComponentStyle}> { this.props.navigation.state.params.Email } </Text>
<FlatList
data={ this.state.dataSource }
ItemSeparatorComponent = {this.FlatListItemSeparator}
renderItem={({item}) => <View style={{flex: 1, flexDirection: 'row'}}> <Text style={styles.points}>+ {item.points}</Text>
<Text style={styles.flatview} onPress={this.GetFlatListItem.bind
(this, item.description, item.tutorial, item.image, item.title)} >{item.title}</Text></View>}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
class Details extends Component{
onPress = () => {
this.setState({
const {goBack} =this.props.navigation;
})
}
return(
<View style = { styles.MainContainer }>
<TouchableHighlight
style={styles.buttonStyle}
onPress={this.onPress}
>
<Text> Got it! </Text>
</TouchableHighlight>
<Text style = {styles.TextComponentStyle}> { this.props.navigation.state.params.Title } </Text>
<Image
style={{width: 66, height: 58}}
source={{uri: this.props.navigation.state.params.Imagen}}
/>
<Text style = {styles.TextComponentStyle}> { this.props.navigation.state.params.Tutorial } </Text>
</View>
);
}
export default MainProject = createStackNavigator(
{
First: { screen: App },
Second: { screen: ProfileActivity },
Fourth: { screen: Details }
});
What i think is pass some values to the method onPress() in Details class, but i don't know which one exactly and how. Can somebody help me?
You will have to create this.state.someArrayName and copy from this.props.navigation.state.params and add backgroundColor key to each object and add your color. Apply that color to your items' view background color. *{{backgroundColor : item.backgroundColor}}
Create a function changeColor to change the color of backgroundColor
In your GetFlatListItem function, pass that function to detail view
On Detail View, call that changeColor function. this.props. changeColor() when you tap Got it button.

How to identify which view is clicked programmatically

I am developing an android application on react native. Which has several buttons and I want to perform different actions on click of each button.
I am quite familiar with android sdk, in android sdk android:id attribute is present to identify components. But the problem in react native is how to identify which button is clicked by user.
<View style = { styles.button_container } >
<Text
onPress={() => } >Component
</Text>
<Text
onPress={() => } >About
</Text>
</View>
you can send a parameter with the button clicked, something like this:
function MenuComponent(props) {
return (
<View style = { styles.button_container } >
<Text
onPress={() => props.onClick('component')} >Component
</Text>
<Text
onPress={() => props.onClick('about')} >About
</Text>
</View>
)
}
Assuming you are sending an onClick prop from the parent. The the parent will know which of the children elements was clicked.
class ParentComponent extends Component {
onClickMenu = (button) => {
console.log(button);
}
render() {
return (
<View>
<MenuComponent onClick={this.onClickMenu} />
</View>
);
}
}
The onClickMenu will get the button param with the clicked button on the child component, from there you can decide what to do for each case.

React native: disable auto clicking on each card when the view is rendered

I got a response from API which i then parse and display some features on the screen using nativebase.io cardlist. When all the results are shown i want each card be clickable and each click leading to the next screen of details depending on a particular card's content. However, when the cardlist is rendered for some reason EVERY card is being clicked without the user interaction. So i'm looking for the solution which would allow a card click only when i touch any particular card.
class Results extends Component{
constructor(props){
super(props);
this.state = {
data: this.props.results
}
}
renderRow(item){
const bars = [ require('../assets/bar0.png'),
require('../assets/bar1.png'),
require('../assets/bar2.png'),
require('../assets/bar3.png')]
var bar = item.weight === -1 ? bars[0] : bars[item.weight]
return (
<CardItem button onPress={console.log("Pressed")} style={{width: 400}}>
<Thumbnail source={bar}/>
<Text>{item.label}</Text>
<Text note style={{textDecorationLine: 'line-through'}}>{item.excluded}</Text>
</CardItem>
)
}
render(){
console.log(this.state.data)
return (
<Container>
<Header>
<Title>symptoma</Title>
</Header>
<Content>
<Card dataArray={this.state.data}
renderRow={(item) =>
this.renderRow(item)
}>
</Card>
</Content>
</Container>
);
}
}
export default Results
replace
onPress={console.log("Pressed")}
with
onPress={() => console.log("Pressed")}