React Navigation Stack doesn't cover whole screen on desktop - react-native

I'm using React Native Web to build a simple Reddit Clone.
I came across this issue while using a StackNavigator from React Navigation.
The stack 'screen' seems to get calculated by the dimensions of the monitor, instead of the content. So when a screen before the currently navigated screen has a larger height than the current screen, the content is still visible 'behind/below' the stack screen.
My homescreen:
<View style={{ flex: 1, backgroundColor: colors.background }}>
<Button style={{ margin: 5 }} action={() => props.navigation.navigate('CreatePost')}><DText>Create post</DText></Button>
<FlatList
data={getPosts}
renderItem={renderPost}
keyExtractor={item => item.id}
/>
</View>
My createpost screen:
<View style={{ flex: 1, backgroundColor: 'red' }}>
<View style={styles.element}>
<TextInput
placeholder={'Title'}
onChangeText={setTitle}
value={getTitle}
/>
<View style={styles.editor}>
<SlateEditor setBody={setBody} />
</View>
<Button action={() => onCreate(getTitle, getBody)}><DText>Post</DText></Button>
</View>
</View>
Here is an example:
I don't want to the user to be able to scroll on the CreatePost screen.

This is fixed by updating #react-navigation/stack to 5.12.6.
See https://github.com/react-navigation/react-navigation/commit/da35085f1e3440f26eea800c892c88aec64d072f

Related

React Navigation 6 - how to close modal from navigation stack

I am trying to close a React Navigation modal from the navigation stack.
Following the official React Navigation documentation navigation.goBack''' is being used within the '''Modal Screen. This successfully closes the modal, but what I would like to achieve is closing the modal by pressing a button in the navigation stack instead of in the screen.
I have tried both of the below functions and although they work as expected in the Screen, they do not work in the stack navigator.
<Button onPress={() => navigation.pop()} title="Dismiss" />
<Button onPress={() => navigation.goBack()} title="Dismiss" />
I get the following error:
undefined is not an object (evaluating 'navigation.goBack')
How can I get the modal to close by pressing a button in the stack navigator?
I think you have misunderstood this Example.
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>This is the home screen!</Text>
<Button
onPress={() => navigation.navigate('MyModal')}
title="Open Modal"
/>
</View>
);
}
function ModalScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 30 }}>This is a modal!</Text>
<Button onPress={() => navigation.goBack()} title="Dismiss" />
</View>
);
}
const RootStack = createStackNavigator();
function RootStackScreen() {
return (
<RootStack.Navigator>
<RootStack.Group>
<RootStack.Screen name="Home" component={HomeScreen} />
</RootStack.Group>
<RootStack.Group screenOptions={{ presentation: 'modal' }}>
<RootStack.Screen name="MyModal" component={ModalScreen} />
</RootStack.Group>
</RootStack.Navigator>
);
}
Note:
both HomeScreen and ModalScreen are screen not model of any kind. screenOptions is an object where you define what type of animation you want to see when user navigate to that screen.
when you set screenOptions to model:
The modal behavior slides the screen in from the bottom and allows the
user to swipe down from the top to dismiss it on iOS.
Finally let talk about your error:
undefined is not an object (evaluating 'navigation.goBack')
navigation props will only be available on those screen which are include in your navigation.
so check that screen is present or not where your accessing navigation.goBack

react-native-gesture-handler Swipable does not take the entire screen

I have the following code:
<View style={{ backgroundColor: 'black'}}>
<ArticleSwipable
ref={swipeableRef}
renderRightActions={this.renderRightActions}
onSwipeableClose={() => console.log('close')}
onSwipeableOpen={loadArticleSwipe}
onSwipeableWillOpen={() =>{ setzIndex(100); }}>
<ArticleScreen
article={article}
navigation={navigation}
scrollRef={scrollRef}
header={<Header
onFavouritePress={toggleFavouriteButton}
favouriteButtonIcon={favouriteButtonIcon} />}
isLoading={isLoading}/>
</ArticleSwipable>
<LoadingComponent opacity={loadingFadeAnim} zIndex={zIndex} isLoading={isLoading} />
</View>
where ArticleSwipable is a react-native-gesture-handler/Swipable component but with overridden close method.
ArticleScreen has the following structure:
<View>
<ScrollView>...</ScrollView>
</View>
My goal is to make the Swipeable Component take the entire screen but now if the content is less than the height of the screen will display the white rectangle at the bottom.
Example
If the content is bigger than the height of the screen then everyting is ok.
How can I get rid of the white rectangle at the bottom?
Try this once :
<View style={{ backgroundColor: 'black' ,flex:1}}>
<ArticleSwipable
ref={swipeableRef}
renderRightActions={this.renderRightActions}
onSwipeableClose={() => console.log('close')}
onSwipeableOpen={loadArticleSwipe}
onSwipeableWillOpen={() =>{ setzIndex(100); }}>
<ArticleScreen
article={article}
navigation={navigation}
scrollRef={scrollRef}
header={<Header
onFavouritePress={toggleFavouriteButton}
favouriteButtonIcon={favouriteButtonIcon} />}
isLoading={isLoading}/>
</ArticleSwipable>
<LoadingComponent opacity={loadingFadeAnim} zIndex={zIndex} isLoading={isLoading} />
</View>
And also this :
<View style={{flex:1}} >
<ScrollView>...</ScrollView>
</View>

How to "lock" the position of a component on react native screen?

I am trying to build the profile screen of a user on my social networking app. The way I want it is the top 1/3 of the screen is the user profile information, and the bottom 2/3 is a flatlist of all the user's posts. Currently, I have that all working logic wise. Here is a screenshot from the app:
As you can see, the user profile information is displaying up top, and the user's post history is correctly being displayed in a flat list below. However, the flat list is pushing the user profile information "up" on the screen.
Here is the code for the profile:
class Profile extends React.Component {
constructor(props) {
super(props)
this.state = {
user: this.props.user
}
}
goToSettings = () => {
this.props.navigation.navigate('Settings')
}
render() {
return (
<View style={styles.container}>
<View style={{ flexDirection: "row", padding: 20 }}>
<Text style = {styles.subheader}> {this.state.user.username} </Text> <------The username is being pushed up, where only the bottom half of it is visible
<TouchableOpacity
onPress={this.goToSettings}>
<Ionicons name="ios-settings" size={24} color="black" />
</TouchableOpacity>
</View>
<View style = {styles.lineStyle} />
<View style={{ flexDirection: "row" }}>
<ProfilePic/>
<ProfileStats/>
</View>
<View style = {styles.lineStyle} />
<ProfileBio />
<View style = {styles.lineStyle} />
<View style={{ flexDirection: "row", alignItems: 'center', justifyContent: 'center' }}>
<CurrentUserPostFeed navigation = {this.props.navigation} /> <------ This is the flat list. It is pushing up the views & other components that are above it.
</View>
</View>
)
}
}
I want the position of the user profile information to stay in the same postition, taking up the top 1/3 of the screen, while the user can scroll through the flatlist which only takes up the bottom 2/3 of the screen
However, I am not sure how to "lock" the profile information in place, where it is always visible in the top 1/3 of the profile screen, no matter how big/small the flatlist of posts becomes. Any advice?
EDIT: It seems that the margin/padding in the cells of the flatlist are causing my issue. Is there a way that I can prevent the flatlist container from pushing the elements above it "up" when I add marginTop or paddingTop?
You should use the flex property to set which
specifies how much of the remaining space in the flex container should be assigned to the item
More info about the flex property here.
** flex is a shorthand for flex-grow.
So, you can do something like this:
<View> // main container
<View style={{flex: 1}}> // header container
// Header Content
</View>
<View style={{flex: 2}}> // flatlist container
// Flatlist content
</View>
</View>
Basically what we are doing here is setting the header to use 1/3 of the available space of main-container and flatlist to use 2/3 of the available sapce of the main-container.

React Navigation Top Bar Getting Same Height (NOT) dependent on its own components

Looking at this example from React Navigation website, between Chat and Contacts, the heights are independent of each other. However, When I tried to implement a top bar, the heights are the same. It takes the height of which ever tab has the most content in it.
But in the example, you can see in Contacts that there may be more contacts where you can scroll, and in Chat, the input field is at the bottom, making it look like that's where it stops.
Here's a screen shot from the example:
Chat tab
Contacts tab
Here's some of my code and what I'm experiencing:
<View style={{backgroundColor: 'orange'}}>
{!loading &&
!loadingProfileInfo &&
typeof data.infoByUser !== 'undefined' && (
<FlatList
data={data.infoByUser}
ListHeaderComponent={
<View>
<UserInfo />
<Tab.Navigator>
<Tab.Screen
name="Test"
component={TestComponent} />
<Tab.Screen
name="New Tab"
component={NewTabComponent}
/>
</Tab.Navigator>
</View>
}
numColumns={2}
renderItem={({item}) => (
<View>
// ...
</View>
)}
keyExtractor={item => item._id}
/>
)}
</View>
TestComponent
<View style={{backgroundColor: 'grey'}}>
<View>
<Text>Test Test</Text>
</View>
<View>
<Text>Test Test</Text>
</View>
<View>
<Text>Test Test</Text>
</View>
<View>
<Text>Test Test</Text>
</View>
<View>
<Text>Test Test</Text>
</View>
</View>
NewTabComponent
<View style={{backgroundColor: 'red'}}>
<Text>new tab</Text>
</View>
Notice how the New Tab has a big gap between the red and the orange, that's from the Test tab's height.
You are rendering your entire navigator as the FlatList 'header'. You shouldn't even use Flatlist in this component. Each screen has a different number of items, and should have its own Flatlist.
To fix this:
Remove the FlatList from your main component (with backgroundColor: 'orange'), and just render the Tab Navigator in that render function.
Inside of TestComponent and NewTabComponent, render a ScrollView (or FlatList) if you need it.
All screens (TestComponent and NewTabComponent) should have a height: '100%' or flex: 1 if you want all screens to take all up all the space of the screen, even when its real height is less than the screen height.
To have heights according to the content inside the particular tab, use Scrollview inside each tab screen. Thank me later if this works perfectly. :)
import * as React from "react";
import { ScrollView, Text, View } from "react-native";
import { createMaterialTopTabNavigator } from "#react-navigation/material-top-tabs";
function Screen1() {
return (
<ScrollView>
<View style={{ flex: 1, alignItems: "center" }}>
<Text style={{ padding: 10 }}>Screen1 </Text>
</View>
</ScrollView>
);
}
function Screen2() {
return (
<ScrollView>
<View style={{ flex: 1, alignItems: "center" }}>
<Text style={{ padding: 10 }}>Screen2</Text>
</View>
</ScrollView>
);
}
function Screen3() {
return (
<ScrollView>
<View style={{ flex: 1, alignItems: "center" }}>
<Text style={{ padding: 10 }}>Screen3 </Text>
</View>
</ScrollView>
);
}
const Tab = createMaterialTopTabNavigator();
export default function TopBarNavigator() {
return (
<Tab.Navigator>
<Tab.Screen name="Screen1" component={Screen1} />
<Tab.Screen name="Screen2" component={Screen2} />
<Tab.Screen name="Screen3" component={Screen3} />
</Tab.Navigator>
);
}
I'm having no idea why you're rendering it inside FlatList as it also inherits props from Scroll View.
<View style={{backgroundColor: 'orange'}}>
<Tab.Navigator>
<Tab.Screen
name="Test"
component={TestComponent} />
<Tab.Screen
name="New Tab"
component={NewTabComponent}
/>
</Tab.Navigator>
</View>
and move the FlatList and other business logics inside the TestComponent or the NewTabComponent.
The point is don't render Tabs inside ScrollView or FlatList or SectionList as they both inherit the props of ScrollView.
After a long research I found out that your problem is because react-native-tab-view (which is used by material-tob-tabs), has this code :
_defineProperty(this, "handleLayout", e => {
const {
height,
width
} = e.nativeEvent.layout;
if (this.state.layout.width === width && this.state.layout.height === height) {
return;
}
this.setState({
layout: {
height,
width
}
});
With option lazy={true} , and using the "New Tab" component on first tab and "Test" on second, you get the right height until you change the tab. When you press on "Test" the layout changes so the height is bigger. After changing tab the height does't change anymore because the layout stays the same ("New Tab" fits perfectly in the bigger height) and doesn't trigger handleLayout from react-native-tab-view.
Hope you can find a way to change the layout again when you change tabs.

ReactNative - FliatList turns white screen when render many item

Android : 4.4.2 , 8.0
React-native : 0.61.4
It only happens on android.
https://gfycat.com/flimsyastonishingguineafowl
<FlatList
style={{ transform: [{ scaleY: -1 }], marginBottom: 10 }}
removeClippedSubviews
initialNumToRender={20}
data={replyList}
onEndReached={this.nextPage}
contentContainerStyle={{ justifyContent: 'flex-end', flexGrow: 1 }}
keyboardShouldPersistTaps="handled"
pinchGestureEnabled={false}
keyboardDismissMode="none"
keyExtractor={item => `${item.replyUID}reply`}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => (
<RenderReplyItem
item={item}
/>
)}
onScroll={handleScroll}
ref={setRef}
scrollEventThrottle={16}
/>
export default class RenderReplyItem extends PureComponent {
render() {
const {
item,
} = this.props;
return (
<View style={[styles.replyContainer, { alignSelf: 'center', transform: [{ scaleY: -1 }] }]}>
<View style={styles.replyBackground}
>
<Text style={styles.replyContentStyle}
>
{item.content}
</Text>
<View style={styles.replyBottom}>
<Text style={styles.replyregisterDate}>
{item.replyUID}
</Text>
</View>
</View>
</View>
);
}
}
The screen turns white after 80 items have been rendered.
Then scroll down again and the screen will come back and the scroll will move randomly.
Other FlatLists experienced a similar phenomenon and disappeared after setting keyExtractor.
However, only after this page, the same thing happens after you set the keyExtractor.
duplicate of
alternative of flatlist in react-native with much improved performance
For improving flatlist performance tips see here