So, I'm using 2 files: The components.js where I define all parts and molds I'll use in my app, and the App.js, which has the logic and major stuff.
To sum things up, I've defined a Card class in the components.js that has a button at the end. Here is the code for the Card:
export class Card extends Component {
render() {
return (
<View style={{height: 700}}>
<View style={{flex: 8, backgroundColor: 'white', borderRadius: 20}} >
<Image source={{uri: this.props.pic}} style={styles.img}/>
<Text style={{flex: 1, fontWeight: 'bold',fontSize: 30, paddingTop: 10}}> {this.props.nome}</Text>
<Text style={{flex: 1, fontSize: 20}}> {this.props.descricao}</Text>
<TouchableHighlight style={{flex: 1}} onPress={() => ???????} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>Mais informações</Text>
</View>
</TouchableHighlight>
</View>
</View>
);
}
}
And I use it in the App.js as follows:
import {Card} from "./components.js";
class App extends Component {
render() {
return (
<View style={{flex: 1, backgroundColor:"#e6e6e1"}}>
<ScrollView>
{this.state.locations.map((pico, key) =>
<Card key={key} pic={pico.img[0]} nome= {pico.nome_do_pico} descricao={pico.how}/>
)}
</ScrollView>
</View>
);
}
}
(I've omitted the parts where it gets the info from the server and puts into the locations array)
What I need is for the button to navigate to another screen, called "Details", and I have tried a few things on the onPress but nothing has worked so far. The documentation for reactnavigation uses this.state.navigation.navigate("Details") as example, but since the Card is in another file it can't access the this.state.navigation. Any ideas?
Try if you can solve the problem by modifying the following part of your code:
in app.js
<Card key={key} pic={pico.img[0]} nome= {pico.nome_do_pico} descricao={pico.how} navigation={navigation}/>
in components.js:
<TouchableHighlight style={{flex: 1}} onPress={() => navigation.navigate('Details', {YourParameters: xx } } underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>Mais informações</Text>
</View>
</TouchableHighlight>
Related
As title says, I need to create a modal popup for every list item for the selected sizes to be displayed. I'm using the react-native-popup-dialog but without results. Could you help me? Here's my code:
step1 = () => {
return (
<View style={{ flex: 8}}>
<Text h3 style={{ ...styles.title, marginVertical: 10.0 }}>{this.state.user=="User"?"Size":"CargoSize"}</Text>
<ScrollView>
<View style={{ marginHorizontal: 16.0 }}>{
this.state.size.map((l, i) => (
<ListItem key={i} onPress={() => this.setState({sizeSelected: i, sizeName: l.title, sizeId: l.id})} underlayColor='transparent'
containerStyle={{backgroundColor: this.state.sizeSelected==i?'#F76858':'white', borderWidth: 1.0,
borderColor: '#707070', marginBottom: 10.0, paddingVertical: 5.0, paddingHorizontal: 40.0}}>
<ListItem.Content>
<View style={{
flexDirection: 'row', alignItems: 'center',
justifyContent: 'center'
}}>
<Text style={styles.textSize}>{l.title}</Text>
<Text style={{ fontSize: 16 }}>{l.example}</Text>
</View>
</ListItem.Content>
</ListItem>
))
}</View>
</ScrollView>
</View>
);
}
I believe you can declare a single modal in your list component and show or hide the modal when the user presses the listItem. Also, make the pressed item active and pass the item to your modal so that the modal can show the details of the active item.
App.js
export default function App() {
const [modalVisible, setModalVisible] = React.useState(false);
const [activeItem, setActiveItem] = React.useState(null);
const onPress = (item) => {
setActiveItem(item)
setModalVisible(true)
}
const renderItem = ({ item }) => (
<TouchableOpacity onPress={()=>onPress(item)}>
<Item title={item.title} />
</TouchableOpacity>
);
return (
<View style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
<Popup modalVisible={modalVisible} setModalVisible={setModalVisible} activeItem={activeItem} />
</View>
);
}
Modal.js
export default function Popup({modalVisible, setModalVisible, activeItem}) {
return (
<View style={styles.centeredView}>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text style={styles.modalText}>{activeItem?.title}</Text>
<TouchableHighlight
style={{ ...styles.openButton, backgroundColor: '#2196F3' }}
onPress={() => {
setModalVisible(!modalVisible);
}}>
<Text style={styles.textStyle}>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
</View>
);
}
Here is a working demo for you.
I made something similar in my react-native project and do this:
Made with {useState} the variables i need in my modal, example, the name of my component
Wrap the ListItem component in a Pressable component
Put the onPress={() => {//Put your code here}} function, inside you will put the SetVariable of the variable you want in the modal
The Pressable will update the variable with the wich you want in the modal
i have data from firebase and i want map it to my custom panels but it seems not mapped (my panels do not show up) but when i console log it, the data succesfully retreived. here is my code
constructor(props) {
super(props);
this.state ={
requests:[]
}
}
componentDidMount(){
this.fetchRequests();
}
fetchRequests(){
this.subscriber = firebase.firestore()
.collection("requests").onSnapshot(docs => {
let requests = []
docs.forEach(doc => {
requests.push(doc.data())
})
this.setState({requests})
})
}
buildPanels() {
this.state.requests.map((req, idx) => {
return <View key={idx} style={styles.panel}>
<View style={{flex: 1}}>
<View style={styles.panelRow}>
<Text style={styles.panelText}>Nama Resipien</Text>
<Text style={styles.panelText}>{req.name}</Text>
</View>
<View style={styles.panelRow}>
<Text style={styles.panelText}>Golongan Darah</Text>
<Text style={{flex: 0.5}}>{req.golDarah}</Text>
</View>
</View>
</View>
})
render(){
return(
<View style={styles.container}>
<ScrollView>
{this.buildPanels()}
</ScrollView>
</View>
);
}
Add return method in your code like
buildPanels() {
return this.state.requests.map((req, idx) => {
return <View key={idx} style={styles.panel}>
<View style={{flex: 1}}>
<View style={styles.panelRow}>
<Text style={styles.panelText}>Nama Resipien</Text>
<Text style={styles.panelText}>{req.name}</Text>
</View>
<View style={styles.panelRow}>
<Text style={styles.panelText}>Golongan Darah</Text>
<Text style={{flex: 0.5}}>{req.golDarah}</Text>
</View>
</View>
</View>
})
Code:
<View style={mainContainerStyle}>
<View style={style1}>
{View1}
</View>
<View style={style2}>
{View2}
</View>
<View style={style3}>
{View3}
</View>
<View style={style4}>
{View4}
</View>
</View>
In this case, I want to check: style1, style2, style3, style 4. These are child styling properties.
If I find any style { flexDirection: 'row' }, I should make it 'row-reverse'. How to achieve this? Please help me.
I think you can use a function to do that specific logic
function format(style) {
if (style.flexDirection === 'row') {
return Object.assign({}, style, { flexDirection: 'row-reverse' });
}
return style;
}
and wrap it up:
<View style={mainContainerStyle}>
<View style={format(style1)}>
{View1}
</View>
<View style={format(style2)}>
{View2}
</View>
<View style={format(style3)}>
{View3}
</View>
<View style={format(style4)}>
{View4}
</View>
</View>
I'm still learning ReactJS / React Native and I'm stuck with a stupid thing I'm sure. Here's my case: I want to receive data in my child component and display it in a Modal. So:
I have a function like this (axios, API, ...):
getProductInfo = (product_id) => {
axios.get(
`API-EXAMPLE`
)
.then((response) => {
this.setState({
isVisible: false,
productInfo: response.data
})
console.log(this.state.productInfo);
})
}
I pass the function to my Child Component with the "onModalPress":
<CatalogList productsList={this.state.displayProducts} onModalPress={this.getProductInfo}/>
And here, some info about the Child Component:
const CatalogList = ({productsList, onModalPress}) => (
<Card containerStyle={styles.container}>
<View style={{ padding:20, margin:0, flexDirection: 'row', flexWrap: 'wrap', flex: 1, justifyContent: 'space-between' }}>
{
productsList.map((p, i) => {
return (
<TouchableHighlight key={i} onPress={() => onModalPress(p.id)}>
<View style={style.card}>
<View style={style.content}>
<View style={{width: 170, zIndex: 2}}>
<Text style={style.name}>{p.id}</Text>
<Text style={style.name}>{p.name}</Text>
<Text style={style.winemaker}>Domaine : {p.domain}</Text>
<Text style={style.winemaker}>Origine : {p.wine_origin}</Text>
<Text style={style.aop}>Appellation : {p.appellation}</Text>
</View>
<Image
style={style.image}
source={{ uri: p.image, width: 140, height: 225, }}
/>
</View>
<View style={style.entitled}>
<Text style={[style.priceText, style.cadetGrey]}>{p.publicPriceText}</Text>
<Text style={style.priceText}>{p.subscriberPriceText}</Text>
</View>
<View style={style.row}>
<Text style={[style.price, style.cadetGrey]}>{p.price} €</Text>
<Text style={style.price}>{p.subscriber_price} €</Text>
</View>
<View style={[{backgroundColor: p.label_colour}, style.label]}>
<Text style={style.labelText}>{p.label}</Text>
</View>
<Modal isVisible={false}>
<View style={{ flex: 1 }}>
{/* <Text>{productInfo.rewiew_wine_waiter}</Text> */}
</View>
</Modal>
</View>
</TouchableHighlight>
);
})
}
</View>
</Card>
);
The "p.id" comes from another data (productList) that I get with another Axios API Call. With "p.id" I get the product_id I need in my function
getProductInfo
Everything works and I display the info inside my console.log (this.state.productInfo).
My issue and I think is easy... It's how can I "store/stock" this info I have in the console.log in a const/props to use it in my Modal and call it like in this example:
<Modal isVisible={false}>
<View style={{ flex: 1 }}>
<Text>{productInfo.rewiew_wine_waiter}</Text>
</View>
</Modal>
Of course, any other advice is welcome!
React is all about one-way data flow down the component hierarchy
Let's assume that you have a Container component that fetch all the data:
class MyContainer extends Component{
state = {
myItensToDisplay: []
}
componentDidMount(){
//axios request
.then(res => this.setState({myItensToDisplay: res.itens}))
}
}
Looking good! Now you have all the data you want to display fetched and stored in your container's state. Let's pass it to a Itemcomponent:
class MyContainer extends Component{
// All the code from above
render(){
const itens = this.state.myDataToDisplay.map( item =>{
return(<Item name={item.name} price={item.price} />);
})
return(
<div>
{itens}
</div>
)
}
}
Now you are fetching all the data you want to display in a parent component and distributing that data to it's childrens via props.
To iterate and add views dynamically from array, I'm using following code.
export default class CreateFeedPost extends Component {
constructor(props) {
super(props);
this.state = {
selectedImages: ["1", "2", "3"]
};
}
render() {
let animation = {};
let color = Platform.OS === "android"
? styleUtils.androidSpinnerColor
: "gray";
return (
<View style={{ flex: 1, flexDirection: "column" }}>
<View style={styles.topView}>
<View style={styles.closeButtonView}>
<TouchableHighlight
underlayColor="transparent"
style={styles.closeButton}
onPress={this._closeButtonClicked.bind(this)}
>
<Icon name="times" color="#4A4A4A" size={20} />
</TouchableHighlight>
</View>
<View style={styles.postButtonView}>
<TouchableHighlight
underlayColor="transparent"
style={styles.postButton}
onPress={this._postButtonClicked.bind(this)}
>
<Text style={styles.postButtonText}>Post</Text>
</TouchableHighlight>
</View>
</View>
<View style={styles.profileContainer}>
<View style={{ width: 65, height: 65, padding: 10 }}>
<Image
source={{ uri: global.currentUser.USER_PROFILE_PIC }}
style={styles.profileImage}
/>
</View>
<View style={[styles.middleTextView]}>
<Text style={[styles.memberName]}>
{global.currentUser.USER_NAME}
</Text>
</View>
</View>
<Animated.ScrollView
style={{ flex: 1 }}
scrollEventThrottle={1}
showsVerticalScrollIndicator={false}
{...animation}
>
<View>
<TextInput
ref="postTextInputRef"
placeholder="So, What's up?"
multiline={true}
autoFocus={true}
returnKeyType="done"
blurOnSubmit={true}
style={styles.textInput}
onChangeText={text => this.setState({ text })}
value={this.state.text}
onSubmitEditing={event => {
if (event.nativeEvent.text) {
this._sendCommentToServer(event.nativeEvent.text);
this.refs.CommentTextInputRef.setNativeProps({ text: "" });
}
}}
/>
</View>
</Animated.ScrollView>
<KeyboardAvoidingView behavior="padding">
<ScrollView
ref={scrollView => {
this.scrollView = scrollView;
}}
style={styles.imagesScrollView}
horizontal={true}
directionalLockEnabled={false}
showsHorizontalScrollIndicator={false}
decelerationRate={0}
snapToInterval={100}
snapToAlignment={"start"}
contentInset={{
top: 0,
left: 0,
bottom: 0,
right: 0
}}
>
{this.state.selectedImages.map(function(name, index) {
return (
<View style={styles.imageTile} key={index}>
<View style={styles.imageView}>
<TouchableHighlight
underlayColor="transparent"
style={styles.imageRemoveButton}
onPress={() => this._imageRemoveButtonClicked.bind(this)}
>
<Icon name="times" color="#4A4A4A" size={20} />
</TouchableHighlight>
</View>
</View>
);
})}
</ScrollView>
<TouchableHighlight
underlayColor="transparent"
style={styles.cameraButton}
onPress={this._cameraButtonClicked.bind(this)}
>
<View style={styles.cameraButtonView}>
<Icon name="camera" color="#4A4A4A" size={20} />
<Text style={styles.cameraButtonText}>Add Pic</Text>
</View>
</TouchableHighlight>
</KeyboardAvoidingView>
</View>
);
}
_closeButtonClicked() {
this.props.navigator.pop();
}
_postButtonClicked() {}
_cameraButtonClicked() {
this.props.navigator.push({
title: "All Photos",
id: "photoBrowser",
params: {
limit: 3,
selectedImages: this.state.selectedImages
}
});
}
_imageRemoveButtonClicked() {
console.log("yes do it");
}
}
I'm loading code in the render method. If I write the function imageRemoveButtonClicked outside render method, it's giving an error saying that 'Cannot read property bind of undefined'. Don't know what to do. Can some one please help me in this.
Use arrow functions and class property feature. For more information about binding patterns read this article. Try to add your method as:
export class App extends Component {
yourMapFunction = () => {
yourCode...
}
}
I believe the problem is that you are not using an arrow function as the argument to this.state.selectedImages.map(). If you want to access this inside an inner function, you should use the arrow function syntax. The standard syntax does not capture this.
this.state.selectedImages.map((name, index) => {
return (...);
})