Reputation: 790
I have a react app with a group of components. I have a group of cards and a popup. What I want is, that whenever a user clicks on a card it should show the popup. My current structure is:
<CardWrapper>
<Popup></Popup>
<Card>...</Card>
<Card>...</Card>
<Card>...</Card>
</CardWrapper>
Right now the CardWrapper
position is relative and the Popup
position is absolute. And whenever a user clicks on a card it will show the Popup
.
But, right now the position to display the Popup
is relative to Cardwrapper
.
no matter where the user clicks the Popup
will always be displayed as
But, I want it to be relative to the card clicked on. like:
if the user clicks on card 2
or if the user clicks on card 4
I don't know how to achieve that. My popup should not be inside my cards. Is there any way to achieve this?
Upvotes: 3
Views: 1339
Reputation: 12215
Ahh , finally thanks to your question , i learned so many things. ive finally achieved what exactly your question is
THis is the working solution Expo link
import * as React from 'react';
import { Text, View, StyleSheet ,FlatList ,TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
import {useRef , createRef , useState} from 'react'
export default function App() {
const data = [1,2,3,4,5,6,7,8,9,10];
const [topH,setTop] = useState(0)
const elementsRef = useRef(data.map(() => createRef()));
const onCardPress = (item,newRef) => {
newRef?.current?.measureInWindow( (fx, fy, width, height, px, py) => {
console.log('Component width is: ' + width)
console.log('Component height is: ' + height)
console.log('X offset to frame: ' + fx)
console.log('Y offset to frame: ' + fy)
console.log('X offset to page: ' + px)
console.log('Y offset to page: ' + py)
setTop(fy)
})
}
const renderEach = ({item,index}) => {
return(
<TouchableOpacity onPress={() => onCardPress (item,elementsRef?.current[index])} style={styles.eachCard} ref={elementsRef?.current[index]} >
<Text>{item}</Text>
</TouchableOpacity>
)
}
const Popup = () => {
if(topH === 0 ){
return null
}
return(
<View style={{backgroundColor:'yellow' , position:'absolute',zIndex:3 , height:60,width:60 , right:30 , top:topH}} >
<Text> popup </Text>
</View>
)
}
return (
<View style={styles.container}>
<View style={{flex:1}} >
<Popup />
<FlatList
style={{flex:1}}
data={data}
renderItem={renderEach}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
// justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
eachCard:{
height:100,
margin:10,
justifyContent:'center',
alignItems:'center',
backgroundColor:'#850D5F'
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
so here basically if you see we have dynamic refs and also newRef?.current?.measureInWindow
is the one which gives us layout position wrt to Y which is relative to frame, and im setting the same in top
position
Please feel free for doubts. also see the results of what ive achieved. hope its your doubt
Upvotes: 1
Reputation: 430
If you need a component to be in the parent but rendered in the child you can pass it as a prop,
ie
const popup = () => {
return <Popup/>
}
const Parent = () => {
return (
<CardWrapper>
<Card popup={popup}>...</Card>
<Card popup={popup}>...</Card>
<Card popup={popup}>...</Card>
</CardWrapper>
)
Then the Card can render the popup and position is absolutely relative to itself
Upvotes: 1