FlatList inside Tab ScrollView - react-native

I'm trying to create a FlatList using the highScores' keys and values put them inside my ScrollView, but is not rendering... What is wrong?
import React from 'react';
import {
Platform,
ScrollView,
StyleSheet,
Text,
View,
FlatList,
Row
} from 'react-native';
export default function HomeScreen() {
const highScores = { '1': 'a', '2': 'b' };
return (
<View style={styles.container}>
<ScrollView
style={styles.container}
contentContainerStyle={styles.contentContainer}>
<View>
<FlatList
data={highScores}
renderItem={
({ item, index }) =>
<Row highScore={item} index={index} key={index} />
}
/>
</View>
);
}
As you can see I've created one View to render his items. I not getting any error but it doesn't works. Somebody may help me please? Thanks!

Actually, there is a lack of explanation in your question. Though, I answer the relative problems you are facing.
First, Flatlist is also a scrollable component, so using flat list inside the scroll view that doesn't make logic. If you are trying to implement nested scroll view, then you can proceed with it.
Second, No tags were closed in the code. It's incomplete.
Last, you have given JSON object to the Flatlist data props, flatlist can't iterate the object. So you should give an array to make items in the array to be rendered.
The right way to give data props:
const highScores = [
{ '1': 'a' },
{ '2': 'b' },
{ '3': 'c' }
];
Solution to your problem:
import * as React from 'react';
import { Text, View, StyleSheet, ScrollView, FlatList } from 'react-native';
import Constants from 'expo-constants';
const highScores = [{ '1': 'a'}, {'2': 'b' }];
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<ScrollView>
<View style={{ width: '100%', height: '100%' }}>
<FlatList
data={highScores}
renderItem={({ item, index }) => <Text>{JSON.stringify(item)}</Text>}
/>
</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
Cleared ?? If yes, upvote pls

Related

Problem with lining up contents: react native

I'm currently having a problem with the clickable size of a reusable button which includes an icon and text. When I run this code it seems like the entire row becomes clickable when I only want the icon and text to become clickable. Does anyone know how to solve this problem? Thanks
App.js
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import IconTextButton from './components/iconTextButton';
export default function App() {
return (
<View style={styles.container}>
<Text style={{marginTop: 100}}>My First React App! Sike </Text>
<IconTextButton iconFont="ionicons" iconName="pencil" iconSize={25} text="Add Items"/>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'powderblue',
},
});
iconTextButton.js
import React from 'react';
import { StyleSheet, TouchableOpacity, Text, View } from 'react-native';
import Ionicon from 'react-native-vector-icons/Ionicons';
export default function IconTextButton({ iconFont, iconName, iconSize, text, onPress }) {
const getIconFont = (iconFont) => {
switch (iconFont) {
case "ionicons":
return Ionicon;
}
};
const FontIcon = getIconFont(iconFont);
return (
<TouchableOpacity onPress={onPress} style={styles(iconSize).container>
<FontIcon name={iconName} size={iconSize} style={styles(iconSize).buttonIcon}>
<Text style={styles(iconSize).buttonText}>{text}</Text>
</FontIcon>
</TouchableOpacity>
)
}
const styles = (size) => StyleSheet.create({
container: {
backgroundColor: 'pink',
},
buttonIcon: {
backgroundColor: 'yellow',
width: size,
},
buttonText: {
backgroundColor: 'green'
},
})
Along with the code I've tried, I've also tried to keep and as seperate contents whilst adding a flexDirection: 'row' inside styles.container. This keeps the contents in the same line but it still makes the whole row clickable. I've also tried putting everything in a and moving the styles.container to the component and adding a height: size into styles.container. This makes the clickable component limited however, the component is hidden underneath due to the restricted height. I have also tried simply just using instead of making a reusable const that its an input. The same thing applies.
You can wrap your Icon and Text Component in a View component and then wrap it inside a TouchableOpacity Component
Try this or do something like this :
import React from 'react';
import { StyleSheet, TouchableOpacity, Text, View } from 'react-native';
import Ionicon from 'react-native-vector-icons/Ionicons';
export default function IconTextButton({ iconFont, iconName, iconSize, text, onPress }) {
const getIconFont = (iconFont) => {
switch (iconFont) {
case "ionicons":
return Ionicon;
}
};
const FontIcon = getIconFont(iconFont);
return (
<TouchableOpacity onPress={onPress} style={styles(iconSize).container}>
<View style={styles(iconSize).iconTextContainer}>
<FontIcon name={iconName} size={iconSize} style={styles(iconSize).buttonIcon} />
<Text style={styles(iconSize).buttonText}>{text}</Text>
</View>
</TouchableOpacity>
)
}
const styles = (size) => StyleSheet.create({
container: {
backgroundColor: 'pink',
},
iconTextContainer: {
flexDirection: 'row',
alignItems: 'center',
},
buttonIcon: {
backgroundColor: 'yellow',
width: size,
},
buttonText: {
backgroundColor: 'green'
},
})

Can I pass an array to a React Native ScrollView?

I'm trying to create a scrollable view using React Native's ScrollView with code below
import React from 'react';
import { Image, ScrollView, Text, StyleSheet, View, Dimensions } from 'react-native';
const styles = StyleSheet.create({
scrollView: {
height: '100%',
width: '100%',
flexDirection: 'column',
},
item: {
height: '20%',
width: '100%',
},
});
const data = [];
for (let i = 0; i < 30; i++) {
const datum = (
<View style={styles.item}>
<Text style={{ fontSize: 30 }}>{i.toString()}</Text>
</View>
);
data.push(datum);
}
const App = () => (
<ScrollView style={styles.scrollView}>
{data}
</ScrollView>
);
export default App;
Snack URL: https://snack.expo.io/rp6!W!HZm
When I run this code in Snack, seems like I cannot scroll down to the second page. I've checked the official documentation of ScrollView and it is passing ReactElement individually into the view.
RN official doc: https://reactnative.dev/docs/using-a-scrollview
Does this mean I cannot pass an array of elements as the children of a ScrollView? Is there anything I'm missing here?
This should do exactly what you're asking for!
The main thing happening here is the data mapping in the line
{data.map((item, index) => {
return (<View/>)
}}
where you are defining what is inside the scrollview... also your styling was a tad off so I touched it up.
Hope this helps!
import React from 'react';
import { ScrollView, Text, StyleSheet, View, Dimensions, SafeAreaView, TouchableOpacity } from 'react-native';
const { height } = Dimensions.get('screen');
function App() {
const data = [];
for (let i = 0; i < 30; i++) {
data.push('arbitrary datam #' + (i + 1));
}
return (
<SafeAreaView style={{ flex: 1 }}>
<ScrollView style={styles.scrollView}>
{data.map((item, index) => {
return (
<View key={index} style={styles.item}>
<Text style={{ fontSize: 30 }}>{item}</Text>
</View>
);
})}
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
scrollView: {
height: height,
},
item: {
height: height * 0.2,
width: '100%',
},
});
export default App;
Use flat list:
import React, {Component} from 'react';
import{AsyncStorage, View, ScrollView, FlatList} from 'react-native';
import {Text, List} from 'native-base';
class Notes extends Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render () {
return (
<ScrollView>
<View style={{margin: 5, marginTop: 5}}>
<List>
<FlatList
data={this.state.data}
renderItem={({item, index}) =>
<View style={styles.item}>
<Text style={{ fontSize: 30 }}>{item.toString()}</Text>
</View>
}
keyExtractor={(item, index) => index.toString()}
/>
</List>
</View>
</ScrollView>
)
}
}
export default Notes;

How to add a static background image for screens in Material Top Tab Navigator?

I have created two tabs with createMaterialTopTabNavigator from react-navigation. I like to have a single background image for two tabs.
The current behaviour is that when I swipe from tab1 to tab2, the image is also transitioned, but I like to have the background image static when transitioning from tab1 to tab2, and only the contents of the tab to transition when swiped. I have tried wrapping the TabNavigator inside the ImageBackground component, but that is of no use.
I think you can use one of the following solutions:
Style the tabs to have a transparent background and set the background image on a <View> above the navigator. You can find details about styling cards in the React Navigation docs here.
A second option, and the more elegant one I think, is to use a dedicated library for managing transitions in React Navigation. There are a few out there but I personally have used Fluid Transitions and I loved it. If you decide to use this library you can set your background image inside your StackNavigator View. You will need to add a shared prop and you'll be done :)
here is the demo: https://snack.expo.io/#nomi9995/e05080
the better way to use react-native-tab-view and wrap TabView within ImageBackground
yarn add react-native-tab-view
import React, { Component } from "react";
import {
Text,
StyleSheet,
View,
SafeAreaView,
ImageBackground,
Dimensions,
} from "react-native";
import { TabView, SceneMap } from "react-native-tab-view";
const width = Dimensions.get("window").width;
function FirstRoute() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>FirstRoute!</Text>
</View>
);
}
function SecondRoute() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>SecondRoute!</Text>
</View>
);
}
export default class App extends Component {
state = {
index: 0,
routes: [
{ key: "first", title: "First" },
{ key: "second", title: "Second" },
],
};
render() {
const { index, routes } = this.state;
const renderScene = SceneMap({
first: FirstRoute,
second: SecondRoute,
});
return (
<SafeAreaView style={{ flex: 1 }}>
<ImageBackground
style={{ flex: 1, width: width }}
source={{
uri:
"https://firebasestorage.googleapis.com/v0/b/ielts-preps.appspot.com/o/1592920135765?alt=media&token=ec911583-06f9-4315-b66c-cf47de120e85",
}}
>
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={(i) => this.setState({ index: i })}
tabBarPosition="bottom"
/>
</ImageBackground>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({});

React Native conditional rendering not working

I want to have a side menu, with a list of categories and when the user selects a category, it should open a scrollable list, right below the category name, with all the pieces of that category.
So I created two list components, one for the categories (SideMenuList) and one for the furniture pieces. I figured I needed to use conditional rendering to render the second list when the user selects the category.
My code:
Side menu code from app.js
state = {
hideMenu: null,
hideList: null
}
sideMenuShow() {
if(!this.state.hideMenu) {
return(
<SideMenu>
<MenuButton onPress = {() => this.setState({hideMenu: true})}/>
<Text style = {{color: 'white', fontSize: 16, fontWeight: 'bold'}}>Furniture</Text>
<SideMenuList onPress = {() => this.setState({hideList: true})}>
{
this.state.hideList ? console.log('yes') : null
}
</SideMenuList>
</SideMenu>
);
}
else {
return(
<SmallSideMenu>
<MenuButton onPress = {() => this.setState({hideMenu: false})}/>
</SmallSideMenu>
);
}
}
SideMenuList.js
import React, { Component } from 'react';
import { View, FlatList, Text, TouchableOpacity } from 'react-native';
import { CardSection } from './common';
import SideMenuItem from './SideMenuItem';
class SideMenuList extends Component {
render() {
return (
<View style = {{flex: 1}}>
<FlatList
style = {{marginBottom: 2}}
data={[
{key: 'Test'},
{key: 'Test2'},
{key: 'Test3'},
{key: 'Test4'},
{key: 'Test5'}
]}
renderItem={({item}) =>
<TouchableOpacity>
<SideMenuItem
onPress = {this.props.onPress}
text={item.key}
>
{this.props.children}
</SideMenuItem>
</TouchableOpacity>}
/>
</View>
);
}
}
export default SideMenuList;
SideMenuItem.js code
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
const SideMenuItem = (props, {onPress}) => {
return (
<View
style = {{flex: 1}}>
<TouchableOpacity
onPress = {onPress}>
<Text style={styles.itemStyle}>{props.text}</Text>
</TouchableOpacity>
{props.children}
</View>
);
}
const styles = {
itemStyle: {
marginTop: 10,
marginRight: 20,
marginLeft: 10,
color: 'white'
}
};
export default SideMenuItem;
My problem right now is that my onPress event is not changing the value of my state property 'hideList', so I can't even check if my solution would actually work. I'm doing a console log when the value is true but it never appears in my console.
Thanks in advance.
You are rendering your SideMenuItem with a TouchableOpacity wrapping it (in your SideMenuList file).
Probably when you are pressing the button, it's triggering SideMenuList button, instead of SideMenuItem button.
Try to remove the TouchableOpacity from SideMenuList and check if it works.
Hope it helps

How to push TextInput in a FlatList in react native?

I want to learn to use FlatList in react native,but I can't figure how to push elements in data (the FlatList array). Can someone help me ?
Here's my react native code:
import React, { Component } from 'react';
import { FlatList, StyleSheet, Text, Button,View ,TextInput} from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {text: '',
data:[]
};
}
render() {
return (
<View>
<TextInput
style={{height: 40}}
placeholder="Task"
onChangeText={(text) => this.setState({text})}/>
<Button title="Add" onPress={this.addTask} />
<FlatList
renderItem={({item}) => <Text style={styles.item}>{item.key}</Text>}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 22
},
item: {
padding: 10,
fontSize: 18,
height: 44,
}
});
You need to add data prop in the Flatlist Component.
<FlatList
data={[{key: 'a'}, {key: 'b'}]}
renderItem={({item}) => <Text>{item.key}</Text>}
/>
the renderItem is basically looping over elements in the data array. It cannot do that if there is no data. If you are starting with empty data just use data={[]}