I am new to react-native and recently implemented Redux in my app.
The App is for ordering food in Restaurants :)
This is a snippet of my Restaurant-Details Screen with cards, which are representing the different menus:
<View style={{alignItems: 'center'}}>
{menus.map((item) => {
return (
<Card style={{width: '95%'}}>
<TouchableOpacity onPress ={() => this.props.navigation.navigate('Products', { menuId: item.sk_id } ,{bestellung})}>
<CardItem cardBody style={{justifyContent: 'center', alignItems: 'center'}}>
<Text style={styles.textdes}> {item.typ} </Text>
</CardItem>
</TouchableOpacity>
</Card>
)
})}
As you can see the onPress Function navigates to the Product Screen and passes a menuId! (Product Screen shows all the food of a specific menu)
This is my Product.js:
class Products extends Component {
constructor(props) {
super(props);
this.state = {
loading: 1
};
}
componentDidMount = () => {
this.props.fetchProducts();
this.state.menuId;
}
addItemsToCart = (product) => {
this.props.addToCart(product);
}
render() {
const { products, navigation } = this.props
const {params} = this.props.navigation.state;
const menuId = params ? params.menuId : null;
return (
<View style={styles.container}>
<Header style={styles.header}>
<Left>
<Button transparent onPress={() =>
this.props.navigation.goBack()}>
<Icon style={{ fontSize: 35, color: '#FFFFFF'}}
active name="arrow-back" />
</Button>
</Left>
<Body>
<Title style={{ fontSize: 25}}>{menuId}</Title>
</Body>
<Right style={{position: 'absolute', right: 20}}>
<Cart navigation={navigation}/>
</Right>
</Header>
<StatusBar barStyle="light-content" backgroundColor="#383838"
translucent={false} />
<View style={styles.bodyProducts}>
<View>
<Text style={{color:
'#000', fontSize: 50}}>{menuId}</Text>
</View>
<FlatList
data={products}
renderItem={({item}) =>
<Product item={item} addItemsToCart=
{this.addItemsToCart} product={item}/>}
keyExtractor ={(item) => item.id}
/>
</View>
</View>
);
}
}
const mapStateToProps = (state) => ({
products: state.products.items
})
export default connect(mapStateToProps {addToCart,fetchProducts})(Products);
The Product.js fetches products from my product.component.js:
class Product extends Component {
addToCart = () => {
this.props.addItemsToCart(this.props.item)
}
render() {
const { product, menuId } = this.props;
return (
<Card>
<View style={styles.container}>
<Image source={product.picture} style={{width:400,height:150}}/>
<View style={styles.productDes}>
<CardItem cardBody style={{justifyContent: 'center',
alignItems: 'center'}}>
<Text style={styles.font}>{menuId}</Text>
</CardItem>
<Text style={{fontSize: 20}}>€{(product.cost).toFixed(2)}
</Text>
<Text style={{fontSize: 16}}>{product.description}</Text>
<TouchableOpacity onPress={this.addToCart} style=
{styles.addBtn}>
<Text style={styles.text}>Hinzufügen</Text>
</TouchableOpacity>
</View>
</View>
</Card>
);
}
}
export default Product;
The question is now: How can I pass the menuId from product.js to
product.component.js without naviagtion?
I hope I could make clear, what my problem is and looking forward to your solutions and help :)
Maybe you should better separate your React components - which are basically views - and your reducers / side-effect (data fetching...) components.
State is in Redux Store, Views only display what's in store.
If you don't want to pass menuId through navigation params, you can add it to your store state - basically you add a field in your reducer's state to save the currently selected menuId.
In your Restaurant-Details screen, when calling onPress, you dispatch an action with the selectedMenuId to your redux store.
Then in your product screen, you retrieve the selectedMenuId from your redux store.
To understand Redux architecture , I like this gif:
Since you're already using Redux, why not store the menu ID you're currently viewing in your store? When the user selects a menu item, dispatch an action to set the current menu ID. Then use a selector to to get the menu ID in the component you need it.
I hope I haven't misunderstood your issue.
Related
Im trying to implement this relatively popular bottom sheet in React Native by #gorhom.
My aim is to open the bottom sheet from another component. I've tried to follow this answer - here . However, i do not understand what goes in the touchable opacity onPress in my component where it is being called from.
Code below
BottomSheetModalComponent
export default function BottomSheetModalComponent({ref}) {
// ref
const bottomSheetModalRef = useRef<BottomSheetModal>(null);
// variables
const snapPoints = useMemo(() => ['25%', '50%'], []);
// callbacks
const handlePresentModalPress = useCallback(() => {
ref.current?.present();
}, []);
const handleSheetChanges = useCallback((index: number) => {
console.log('handleSheetChanges', index);
}, []);
// renders
return (
<BottomSheetModalProvider>
<View>
<BottomSheetModal
ref={ref}
snapPoints={snapPoints}
onChange={handleSheetChanges}
>
<View>
<Text>Awesome 🎉</Text>
</View>
</BottomSheetModal>
</View>
</BottomSheetModalProvider>
);
};
Location Component
export default function LocationBar() {
// Create Ref
const userBottomSheetRef = useRef<BottomSheetModal>(null);
// Pass ref into the bottom sheet component
<LocationBottomSheet ref={userBottomSheetRef} snapPoints={["30%"]}/>
return (
<>
<View style={{ flexDirection: "row" }}>
<View style={styles.locationBar}>
<Octicons style={styles.locationIcon} name="location" size={18} />
<TouchableOpacity onPress={() => {
//WHAT GOES HERE?
}}>
<Text style={{fontSize: 17, fontWeight: '600'}}>{userLocation}</Text>
</TouchableOpacity>
<Ionicons style={styles.chevronIcon} name="chevron-down" size={12} />
</View>
</View>
</>
);
}
Thanks in advance
I'm new to react native world and I'm trying to integrate a calendar with a time slot picker, so I'm trying to pass the selected date from the calendar to the slot picker page but I'm having this Error when I press on a date in the calendar and I couldn't fix it.
TypeError: undefined is not an object (evaluating 'navigation.navigate')
This is my calendar function:
const RequestMeeting = ({ navigation }) => {
const [isModalVisible, setModalVisible] = useState(false);
const toggleModal = () => {
setModalVisible(!isModalVisible);
};
return (
<View style={{ margin: 100, }}>
<Button title="Show modal" onPress={toggleModal} />
<Modal isVisible={isModalVisible} avoidKeyboard={true} scrollHorizontal={true} propagateSwipe={true}>
<ScrollView>
<View style={{ margin: 50, backgroundColor: 'gray', borderRadius: 20, padding: 20, margin: 20 }}>
<Text style={styles.heading}>Request to Buy/Rent</Text>
<View style={{ paddingBottom: 10 }}></View>
<View >
<Calendar
onDayPress={(day) => navigation.navigate("Slot", { bookingDate: day })}
style={styles.calendar}
hideExtraDays
theme={{
selectedDayBackgroundColor: 'green',
todayTextColor: 'green',
arrowColor: 'green',
}}
/>
</View>
<Button
buttonStyle={styles.register}
title="Send Buy/Rent request"
/>
<Button
buttonStyle={styles.cancelbtn}
title="Cancel"
onPress={toggleModal}
/>
</View>
</ScrollView>
</Modal>
</View>
);
};
And this is my time slot picker function:
const jsonData = {
"slots": {
"slot1": "9:00am to 9:30am",
"slot2": "9:30am to 10:00am",
"slot3": "10:00am to 10:30am",
"slot4": "10:30am to 11:00am",
"slot5": "11:00am to 11:30am",
"slot6": "11:30am to 12:00pm"
}
}
const Slot = ({ navigation }) => {
const onPressBack = () => {
const { goBack } = navigation
goBack()
}
const slots = jsonData.slots
const slotsarr = Object.keys(slots).map(function (k) {
return (
<View key={k} style={{ margin: 5 }}>
<TouchableOpacity >
<Text>{slots[k]}</Text>
</TouchableOpacity>
</View>)
});
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
<View >
<TouchableOpacity onPress={() => onPressBack()}><Text >Back</Text></TouchableOpacity>
<Text ></Text>
<Text ></Text>
</View>
{ slotsarr}
</View>
);
}
This error means that wherever you are rendering RequestMeeting or Slot (whichever one has the error) it's not getting the navigation prop. If it is rendered as a Screen then it will get the prop from the Navigator. If it's not a top-level screen then you need to pass down the prop from a parent or access it with the useNavigation hook.
Docs: Access the navigation prop from any component
I am trying to send prop to other component When I clicked button. I cant send it. I get the Id when I am mapping movies but, I get undefined In movies class.
exampleList= movies.map((x, index) => {
return (
<View key={index} style={{ flex: 1, flexDirection: 'row' }} >
<TouchableOpacity
onPress={() => { navigation.navigate('list'), <Movies movieId={x._id.$oid}/>}}
>
<Text style={styles.buttonText}>{x.movieName}</Text>
</TouchableOpacity>
</View>
)
})
return (
<ScrollView style={{ backgroundColor: '#COE6E7' }}>
{exampleList}
</ScrollView>
);
export default class Movies extends React.Component {
componentDidMount(){
console.log(this.props.movieId)
}
}
Do it like this
onPress={() => navigation.navigate('list', {movieId : x._id.$oid})}
Then in Movies Screen when you will
console.log(this.props.movieId) // This will output MOVIE_ID
I am still trying to finish my first React Native app. There is another thing for which I cannot find a solution.
My application has different Screens (HomeScreen, NewsScreen, etc). Each of these screens uses the component Screen:
const Screen = ({props, children}) => {
console.log("Screen props: " + props);
return (
<>
<OfflineNotice />
<Header {...props} />
<SafeAreaView style={styles.screen}>
<View style={styles.container}>{ children }</View>
</SafeAreaView>
</>
);
}
export default Screen;
Each Screen component has another Header component (there is a dropdown, by choosing another option it will change the displayed information on the screen)
Here is the Header component:
export default function Header (props) {
console.log("Header props: " + props.loadPredictions);
const {sport, setSport} = useContext(AppContext);
const logo = config[sport].logo;
return (
<View style={styles.container}>
<View style={styles.link}>
<TouchableOpacity
onPress={() => props.navigate("Settings")}
>
<MaterialCommunityIcons name="tune" size={32} />
</TouchableOpacity>
</View>
<View style={styles.logo}>
<Image source={logo} style={styles.image} />
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Menu
ref={this.setMenuRef}
button={<MaterialCommunityIcons name="chevron-down" size={24} onPress={this.showMenu} />}
>
<MenuItem onPress={() => {changeSport('soccer', setSport, props)}}>{i18n.t('predictions.p_1')}</MenuItem>
<MenuItem onPress={() => {changeSport('basketball', setSport, props)}}>{i18n.t('predictions.p_3')}</MenuItem>
<MenuItem onPress={() => {changeSport('volleyball', setSport, props)}}>{i18n.t('predictions.p_4')}</MenuItem>
<MenuItem onPress={() => {changeSport('hockey', setSport, props)}}>{i18n.t('predictions.p_5')}</MenuItem>
<MenuItem onPress={() => {changeSport('tennis', setSport, props)}}>{i18n.t('predictions.p_6')}</MenuItem>
</Menu>
</View>
</View>
</View>
);
};
And here is my HomeScreen:
export default function HomeScreen({ navigation }) {
...
useEffect( () => {
loadPredictions(params);
}, []);
const loadPredictions = async (params) => {
...
}
return (
<Screen navi={navigation} loadPredictions={loadPredictions}>
<View style={styles.activity}>
<ActivityIndicator animating={loading} size="large" />
</View>
<View style={styles.main}>
...
</View>
</Screen>
);
}
On the HomeScreen I am passing through the Screen component two props: navi and loadPredictions. Unfortunately, I cannot access them. I am getting the error undefined.
What am I doing wrong?
Simply because you made a distructuring the props in Screen Component, thus if you console log the props you will find it undefined, the best approach that you do this:
const Screen = ({children, ...restProps}) => {
console.log("Screen props: " + restProps);
return (
<>
<OfflineNotice />
<Header {...restProps} />
<SafeAreaView style={styles.screen}>
<View style={styles.container}>{ children }</View>
</SafeAreaView>
</>
);
}
export default Screen;
In this way we will be able to access to children prop and you pass the rest of the Screen Props to what Component you want.
I hope this answer can help you out.
change this
const Screen = ({props, children})
to
const Screen = (props)
and access children props.children
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