Not able to Scroll React Native - javascript

I was creating an app that sells ebooks and when creating the details page for each book, I wrapped the entire component with a scroll view but it does not work, you can see my result in the screen recording attached, I looked through many solutions but could not find a fix for my issue,
Here is my code of the component that's causing the issue:
import React, {useState, useEffect} from 'react';
import axios from '../../axios.config';
import {ScrollView, View, Text, Image, useWindowDimensions} from 'react-native';
import RenderHtml from 'react-native-render-html';
import Button from '../../components/Button';
import OutlineButton from '../../components/OutlineButton';
import Rating from '../../components/Rating';
import Header from './components/Header';
import BookDataRail from './components/BookDataRail';
import {Book} from '../../types/Book';
import {ReadBook, PlayWhite} from '../../icons';
import styles from './styles';
import Review from '../../components/Review';
interface BookDetailsProps {}
const BookDetails: React.FC<BookDetailsProps> = () => {
const [bookDetails, setBookDetails] = useState<Book>();
const {width} = useWindowDimensions();
useEffect(() => {
const getData = async () => {
const {data} = await axios.post('/', {
method: 'bookdetails',
book_id: 4,
});
setBookDetails(data);
};
getData();
}, []);
return (
<View style={{flex: 1}}>
<ScrollView scrollEnabled={true} contentContainerStyle={{backgroundColor: "white", flexGrow: 1}}>
{/* Cover Image/Header */}
<View
style={{
height: '40%',
}}>
<Header coverUrl={bookDetails?.cover_url} />
</View>
{/* Content */}
<View style={styles.body}>
{/* Book Title */}
<Text style={styles.bookTitleText}>{bookDetails?.title}</Text>
{/* Author Name */}
<Text style={styles.authorNameText}>{bookDetails?.author_name}</Text>
{/* Main Rating */}
<View style={styles.ratingContainer}>
<Rating
rating={bookDetails ? bookDetails.rating_review.rating : 0}
/>
</View>
{/* Play Audio/Read Book Buttons */}
<View style={styles.buttonsContainer}>
<Button
title="Play Audio"
width={'48%'}
leftAccessory={
<Image source={PlayWhite} style={styles.buttonIcon} />
}
/>
<OutlineButton
title="Read Book"
width={'48%'}
leftAccessory={
<Image source={ReadBook} style={styles.buttonIcon} />
}
/>
</View>
{/* Add to Wishlist */}
<Text style={styles.addToWishlistText}>+ Add to Wishlist</Text>
{/* Book Details Rail */}
<View style={styles.bookRailContainer}>
{bookDetails && (
<BookDataRail
downloads={bookDetails.downloads}
language={bookDetails.language}
pages={bookDetails.num_pages}
genre={bookDetails.genre_name}
/>
)}
</View>
{/* Book Description */}
<View style={styles.descriptionContainer}>
<Text style={styles.sectionTitle}>Summary</Text>
<ScrollView
nestedScrollEnabled
style={styles.descriptionTextContainer}>
<RenderHtml
contentWidth={width}
source={{html: bookDetails?.description || ''}}
/>
</ScrollView>
</View>
{/* Ratings */}
<View style={styles.ratingsContainer}>
<Text style={styles.sectionTitle}>Reviews</Text>
{/* Ratings Header */}
<View style={styles.ratingsHeader}>
<Text style={styles.ratingText}>
{bookDetails?.rating.toFixed(1)}
</Text>
<View>
<View style={styles.ratingContainerSmall}>
<Rating
rating={bookDetails ? bookDetails.rating_review.rating : 0}
noText
/>
</View>
<Text style={styles.numRatingsText}>
{bookDetails?.rating_review.review_comments.length || 0}{' '}
reviews
</Text>
</View>
</View>
{/* Showing all reviews */}
<View style={styles.reviewCommentsContainer}>
{bookDetails?.rating_review.review_comments.map(
(reviewComment, index) => (
<Review
key={index}
name={reviewComment.name}
rating={reviewComment.rating}
date={reviewComment.date}
comment={reviewComment.comment}
/>
),
)}
</View>
</View>
</View>
</ScrollView>
</View>
);
};
export default BookDetails;
The issue is definitely with the top view that's containing the header, if I remove it it works file, I also tried using it without the Header component inside, but it still does not work...
And here is the result I'm getting
https://drive.google.com/file/d/121x2CNuj3M63aJu_Z1PjxYbYxivCrhuP/view?usp=sharing
Any help would be appreciated,
Thanks

Have you tried to apply contentContainerStyle={{flexGrow: 1}} and container={{flex: 1}}?
Seems like it should do the trick 🙂

How about wrapping the scrollview comp inside a container like below
<View style = {{ flex : 1 }}>
<ScrollView contentContainerStyle = {{ flexGrow : 1 }}>
</ScrollView>
</View>

Related

react-native swipeable gesture not working on android?

I am doing a react native course with Mosh (https://codewithmosh.com/). I am using expo. I am very new to react native and don't really know what I am doing, but I know my code should work. I double-checked my code against his and even went so far as to copy my project over to a friends mac and see if the code works on ios (as mosh is running his code on the ios simulator). On the ios simulator, my code runs perfectly, but on android, nothing happens.
Here is where I implement the swipeable itself:
import React from 'react';
import { StyleSheet, View, Image, TouchableHighlight } from 'react-native';
import Swipeable from 'react-native-gesture-handler/Swipeable';
import AppText from './AppText';
import colors from '../config/colors';
function ListItem({title, subtitle, image, onPress, renderRightActions}) {
return (
<Swipeable renderRightActions={renderRightActions} >
<TouchableHighlight underlayColor={colors.light} onPress={onPress} >
<View style={styles.container} >
<Image style={styles.image} source={image} />
<View>
<AppText style={styles.title} >{title}</AppText>
<AppText style={styles.subTitle}>{subtitle}</AppText>
</View>
</View>
</TouchableHighlight>
</Swipeable>
);
}
I then export this to a different screen:
function MessagesScreen(props) {
return (
<Screen>
<FlatList
data={messages}
keyExtractor={message => message.id.toString}
renderItem={({ item }) => (
<ListItem
title={item.title}
subtitle={item.description}
image={item.image}
onPress={() => console.log('message selected', item)}
renderRightActions={ListItemDeleteAction}
/>
)}
ItemSeparatorComponent={ListItemSeparator}
/>
</Screen>
);
}
the listItemDelete action I am passing into the renderRightActions prop can be seen here:
function ListItemDeleteAction(props) {
return (
<View style={styles.container} ></View>
);
}
Alright so, I found a solution by wrapping the swipeable in a gestureHandlerRootView.
import { GestureHandlerRootView, Swipeable } from "react-native-gesture-handler";
import AppText from "./AppText";
import colors from "../config/colors";
function ListItem({ title, subtitle, image, onPress, renderRightActions }) {
return (
<GestureHandlerRootView>
<Swipeable renderRightActions={renderRightActions}>
<TouchableHighlight underlayColor={colors.light} onPress={onPress}>
<View style={styles.container}>
<Image style={styles.image} source={image} />
<View>
<AppText style={styles.title}>{title}</AppText>
<AppText style={styles.subTitle}>{subtitle}</AppText>
</View>
</View>
</TouchableHighlight>
</Swipeable>
</GestureHandlerRootView>
);
}
I found a solution by wrapping the swipeable in a gestureHandlerRootView.
import { GestureHandlerRootView } from "react-native-gesture-handler";
import AppText from "./AppText";
import colors from "../config/colors";
function ListItem({ title, subtitle, image, renderRightActions }) {
return (
<GestureHandlerRootView>
<Swipeable renderRightActions={renderRightActions}>
<View style={styles.main}>
<Image style={styles.img} source={image} />
</View>
</Swipeable>
</GestureHandlerRootView>
);
}
try this option...
import {
GestureHandlerRootView,
Swipeable,
} from "react-native-gesture-handler";
then wrap on <Swipeable>..</Swipeable>
look example below
<GestureHandlerRootView>
<Swipeable renderRightActions={renderRightActions}>
<TouchableHighlight underlayColor={Colors.ccc} onPress={onPress}>
<View style={styles.view}>
<Image style={styles.image} source={image} />
<View style={styles.details}>
<Txt style={styles.title}>{title}</Txt>
<Txt style={styles.subtitle}>{subtitle}</Txt>
</View>
</View>
</TouchableHighlight>
</Swipeable>
</GestureHandlerRootView>

React Native: I can't set a TextInput value from a 'child' screen

I am working in React Native and I want to set a value in a non-editable TextInput. The value is written on a screen that I am navigating to. Meaning; "parent" screen has the empty input -> I navigate to a "child" screen in which I can enter the value in another TextInput. When I have done that I want to press "OK" and go back to the "parent" screen where the value is displayed.
I have read the documentation as thoroughly as I could, but I still can't get it to work. I can set the value in the "child" screen, but the value is not updated when I navigate back to the parent.
Parent screen
Disregard the code related to equipment, since it will assimilate the barcode logic
import React, { useState } from 'react'
import { Text, TouchableOpacity, View, Image, TextInput } from 'react-native'
import styles from './styles';
import { IMAGE } from '../../constants/Images'
import { CustomHeader } from '../../CustomHeader'
export default function SamplingScreen({ navigation, route }) {
//const [barcodeData, setBarcodeData] = useState('32231321')
const [equipmentID, setEquipmentID] = useState('')
//Guarding against undefined value
const barcode = route.params?.barcode ?? 'Barcode'
return (
<View style={styles.container}>
<CustomHeader title="Sample Oil" navigation={navigation} isHome={true} ></CustomHeader>
<View style={styles.contentContainer}>
<Image
style={styles.logo}
source={IMAGE.ICON_LOGO}
/>
<Text>Send an oil sample for analysis</Text>
<Text>Start by linking a bottle with its barcode</Text>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('BottleID')} /*barcodeData={setBarcodeData}*/ >
<Text style={styles.buttonText} >Link Bottle</Text>
</TouchableOpacity>
<Text>Please link the equipment from which the sample was taken</Text>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('EquipmentID')} equipmentID={setEquipmentID} >
<Text style={styles.buttonText} >Link Equipment</Text>
</TouchableOpacity>
<Text>This is the bottle barcode</Text>
<TextInput
editable={false}
style={styles.input}
defaultValue={barcode}
value={barcode}
underlineColorAndroid="transparent"
autoCapitalize="none">
</TextInput>
<Text>This is the equipment barcode</Text>
<TextInput
editable={false}
style={styles.input}
defaultValue={equipmentID}
value={equipmentID}
underlineColorAndroid="transparent"
autoCapitalize="none">
</TextInput>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>Accept</Text>
</TouchableOpacity>
</View>
</View>
)
}
Child screen
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, TextInput } from 'react-native';
import { CustomHeader } from '../../../CustomHeader'
import styles from './styles'
export default function SetBottleIDScreen({ navigation, route }) {
const [barcodeData, setBarcodeData] = useState('')
console.log(barcodeData)
return (
<View style={styles.container} >
<CustomHeader title="Bottle ID" isHome={false} navigation={navigation} ></CustomHeader>
<Text style={{ marginTop: 30, marginBottom: 30 }} > Set barcode for sampling bottle </Text>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Camera')}>
<Text style={styles.buttonText}>Scan Barcode</Text>
</TouchableOpacity>
<Text style={{ marginTop: 60, marginBottom: 10 }} >Insert Barcode</Text>
<TextInput
style={styles.input}
placeholder='Barcode'
placeholderTextColor="#aaaaaa"
onChangeText={(text) => setBarcodeData(text)}
value={barcodeData}
underlineColorAndroid="transparent"
autoCapitalize="none">
</TextInput>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Sampling', { screen: 'Sampling', params: { barcode: barcodeData }, merge: true })}>
<Text style={styles.buttonText} >OK</Text>
</TouchableOpacity>
</View>
);
}
I am using React Navigation 5.x. I am pretty sure that the value has to be parsed as a parameter with route, but something isn't working as intended.
I solved the issue.
The syntax for setting the parameters were wrong.
It should look like this in stead:
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Sampling', { barcode: barcodeData })}>
<Text style={styles.buttonText} >OK</Text>
</TouchableOpacity>

tab navigation in react native is not working

import React from 'react'
import { View, Text, StyleSheet, TouchableWithoutFeedback } from "react-native";
const Header = props => {
const {
navigationState,
navigation,
activeTintColor,
inactiveTintColor
} = props;
const activeTabIndex = navigation.state.index;
return (
<View style={styles.containerHeader}>
<View style={styles.textContainer}>
<Text style={styles.textWhite}>Win Bets</Text>
<Text style={styles.textWhiteSmall}>win cash daily</Text>
</View>
<View style={styles.tabContainer}>
{navigationState.routes.map((route, index) =>{
const isRouteActive = index === activeTabIndex;
const tintColor = isRouteActive ? activeTintColor : inactiveTintColor;
return (
<TouchableWithoutFeedback
onPress={() => navigation.navigate(route.routeName)}
key={route.routeName}
>
<View>
<Text
style={{
fontSize: 17,
textTransform: "capitalize",
color: `${tintColor}`,
fontWeight: `${isRouteActive ? "700" : "normal"}`
}}
>
{route.routeName}
</Text>
</View>
</TouchableWithoutFeedback>
);
})}
</View>
</View>
);
};
the tabs show as they are supposed to be, but they are not clickable and cant navigate to a different page... also the home page doesnt show.
what could be the problems, or how do i configure the routes and routeName?

Is there a way to change text colour of a text element on a parent component from the child component in React Native?

Is there a way to change the text colour of a text element on a parent component from the child component in React Native?
I have done it with the icon in the code below, can I do it with text?
Discover More Parent Component
import React from 'react';
import {Text, View, TouchableOpacity, StyleSheet} from 'react-native';
import Colors from '#miniclementine:common/appearance/Colors';
import ClementineIcon from '#miniclementine:common/components/ClementineIcon';
export default function DiscoverMore({title, onPress, color}) {
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.btnContainerStyle}>
<ClementineIcon name="add-circle-bold" color={color} size={24} />
<Text style={styles.btnTextStyle}> {title} </Text>
</View>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
btnContainerStyle: {
paddingVertical: 16,
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
},
btnTextStyle: {
color: Colors.cornflower,
fontSize: 16,
textAlign: 'center',
}
});
HomePage bringing in DiscoverMore component and changing colour of icon using props
export default function SessionHomepage({navigation, passData, onPress}) {
const onPressSectionHeader = ({onPress}) => {
navigation.navigate(SESSIONS_LIST_PAGE, passData)
// #TODO: navigate to a page using navigation.navigate(pageName, params);
};
const onPressSectionHeaderInvalid = () => {
alert('Out of scope for this task')
// #TODO: navigate to a page using navigation.navigate(pageName, params);
};
const onContactPress = () => {
Linking.openURL('mailto:alina#clementineapp.co.uk?subject=SendMail&body=Description')
}
return (
<SafeAreaView style={styles.container}>
<ScrollView>
<View style={styles.content}>
<SectionHeader
title="Morning Sessions"
onPress={onPressSectionHeaderInvalid}
/>
<DiscoverMore
title="Discover more sessions"
onPress={onPressSectionHeaderInvalid}
color={Colors.cornflower}
/>
<SectionHeader
title="Pick-me-ups"
onPress={onPressSectionHeader}
/>
<DiscoverMore
title="Discover more sessions"
onPress={onPressSectionHeader}
color={Colors.cornflower}
/>
</View>
<View style={styles.sleepSection}>
<Image
source={require('../../assets/illustrations/sleep_section.png')}
style={{height: 250, width: '100%'}}
/>
</View>
<View style={styles.content}>
<View style={styles.sleepSection}>
<SectionHeader
title="Sleep Sessions"
onPress={onPressSectionHeaderInvalid}
/>
<Text>test</Text>
<DiscoverMore
title="Discover more sessions"
onPress={onPressSectionHeaderInvalid}
color={Colors.powderBlue}
/>
</View>
</View>
<BlueButton title="Leave us feedback" onPress={onContactPress}/>
</ScrollView>
</SafeAreaView>
);
}
Try this way
Discover page
export default function DiscoverMore({title, onPress, color, textColor}) {
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.btnContainerStyle}>
<ClementineIcon name="add-circle-bold" color={color} size={24} />
<Text style={[styles.btnTextStyle,{color: textColor}]}> {title} </Text>
</View>
</TouchableOpacity>
);
}
Home Page
<DiscoverMore
title="Discover more sessions"
onPress={onPressSectionHeaderInvalid}
color={Colors.cornflower}
textColor={Colors.cornflower} // add text color here
/>

How to use react native navigation to navigate from a FlatList component to a expanded component

I am creating a basic blog application using ReactNative. The home screen renders a FlatList of posts with a title, key, and author. I want to be able to click on an individual post and navigate to a new screen that has the full blog post. I will try and give as much code as possible to explain my problem.
// ./Post
function Post(props) {
const navigation = useNavigation();
return (
<TouchableOpacity
style={styles.container}
onPress={() =>
navigation.navigate({ name: "ExpandedPost", params: props.id })
}
>
<View>
<Text style={styles.post}>This is the title to a fake post</Text>
<Text style={styles.text}>By {props.Author} </Text>
</View>
<Image
source={{ uri: "https://picsum.photos/200/300" }}
style={styles.thumbnail}
/>
</TouchableOpacity>
);
}
// ./ExpandedPost
export default function ExpandedPost({ navigation, route }) {
return (
<View style={styles.container}>
<View>
<Text style={styles.post}>This is the title to a fake post</Text>
<Text> This is a body of a fake post</Text>
</View>
<Image
source={{ uri: "https://picsum.photos/200/300" }}
style={styles.thumbnail}
/>
</View>
);
}
// ./PostList
const RenderPosts = () => {
return (
<FlatList
data={fakePosts}
renderItem={({ item }) => <Post Author={item.Author} />}
/>
);
};
export default function PostList() {
return (
<View style={styles.container}>
<Header />
<RenderPosts />
</View>
);
}
Basically, I want to take the post that is rendered in PostList, and onPress I want to navigate to ExpandedPost that contains all of the data from the specific post.
This might help
// ./Post
function Post(props) {
const navigation = useNavigation();
return (
<TouchableOpacity
style={styles.container}
onPress={() =>
navigation.navigate("ExpandedPost", {item: props.item})
}
>
<View>
<Text style={styles.post}>This is the title to a fake post</Text>
<Text style={styles.text}>By {props.item.Author} </Text> <-- Change here -->
</View>
...
</TouchableOpacity>
);
}
// ./ExpandedPost
export default function ExpandedPost(props) {
const completeItemOfPost = props.item; <-- Complete Item Here -->
return (
<View style={styles.container}>
<View>
<Text style={styles.post}>This is the title to a fake post</Text> <-- You can show title like "completeItemOfPost.title" -->
<Text> This is a body of a fake post</Text> <-- You can show body like "completeItemOfPost.body" -->
</View>
<Image
source={{ uri: "https://picsum.photos/200/300" }} <-- You can show image like "completeItemOfPost.image" -->
style={styles.thumbnail}
/>
</View>
);
}
// ./PostList
const RenderPosts = () => {
return (
<FlatList
data={fakePosts}
renderItem={({ item }) => <Post item={item} />} <-- Pass complete item here... -->
/>
);
};}

Categories

Resources