How to push TextInput in a FlatList in react native? - 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={[]}

Related

FlatList inside Tab ScrollView

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

How to make FlatList fill the height?

import React from 'react';
import {SafeAreaView, KeyboardAvoidingView, FlatList, View, Text, TextInput, Button, StyleSheet } from 'react-native';
export default class Guest extends React.Component {
state={
command: '',
}
constructor(props) {
super(props)
this.onChangeText = this.onChangeText.bind(this)
this.onKeyPress = this.onKeyPress.bind(this)
this.onSubmit = this.onSubmit.bind(this)
}
onChangeText(text){
const command = text.replace('\n', '');
this.setState({
command: command
})
}
onKeyPress(e){
}
onSubmit(){
}
render() {
return(
<SafeAreaView style={styles.safeAreaView}>
<KeyboardAvoidingView style={styles.keyboardAvoidingView} keyboardVerticalOffset={88} behavior="padding" enabled>
<FlatList
inverted={true}
keyboardShouldPersistTaps='always'
keyboardDismissMode='interactive'
ref='list'
style={styles.flatList}
data={[1, 2, 3]}
renderItem={(props) => {
return(<View><Text>{props.item}</Text></View>)
}}
/>
<TextInput
command={this.state.command}
onChangeText={this.onChangeText}
onKeyPress={this.onKeyPress}
onSubmit={this.onSubmit}
style={styles.textInput}
/>
</KeyboardAvoidingView>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
safeAreaView:{
backgroundColor:"#ffffff",
},
keyboardAvoidingView:{
},
flatList:{
backgroundColor: 'red',
},
textInput:{
backgroundColor: 'yellow'
}
})
I'd like the red flatList to fill the screen (but keep height of yellow textbox).
I've tried flex:1 on flatList, but it simply makes it disappear.
FlatList inherits ScrollView's props, so solution for ScrollView will work:
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
{...otherProps}
/>
Here is the original Github issue for above solution.
EDIT: The parental Views of FlatList should have flex: 1 in their style.
safeAreaView:{
backgroundColor:"#ffffff",
flex: 1
},
keyboardAvoidingView:{
flex: 1
},
use the property style wit flex:
render() {
return (
<View style={{ flex: 1 }}>
<FlatList
keyExtractor = { this.keyExtractor }
data = { this.getPOs() }
ListEmptyComponent = { this.renderEmpty }
ItemSeparatorComponent = { Separator }
renderItem = { this.renderItem }
/>
</View>
)
}
No need to add a parental view to the list, simply:
render() {
return <FlatList style={{width: '100%', height: '100%'}}
{...others}
/>;
}
you can also add height in flatList style or put flatlist inside a view and then add flex for view
In my case the problem was with virtual keyboard. when I open another page. then the keyboard suddenly dismiss. and it cause part of the page to be like someone cut it or clean it. so the solution is to before push the page that contain flatlist first dismiss the keyboard and then navigate to new page
I try every response on this issue but none of them work.
What I do was add a Parent to the FlatList and then give it a style :
<View style={{ height: SCREEN_HEIGHT}}>
SCREEN_HEIGHT is from Dimensions.get('window')
you have to import from "react-native" like this:
import { Dimensions } from "react-native"
Full example:
<View style={{ height: SCREEN_HEIGHT}}>
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
keyExtractor={item => item.name}
numColumns={1}
data={this.state.dataList}
renderItem={({ item, index }) =>
this._renderItemListValues(item, index)
}
/>
</View>

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

State does not change until the second button press? Adding a call back throws an error "invariant violation: invalid argument passed"

I'm trying to render a Flatlist that contains a store name. Upon clicking the store name, more information about the store should be displayed.
I attempted to change state and then use
{this.renderMoreDetails(item) && this.state.moreDetailsShown}
to get the additional information to appear. However, it was clear via console.log that state was only changed after a second button press.
From what I read in this article 1 and this article 2 it seemed as though I needed a callback function as an additional parameter to my setState().
I tried adding a callback function(probably incorrect, but I'm extremely lost at this point) and only got more errors.
I know that I have access to all of the data from renderItem inside FlatList. How do I make it appear upon click?
import React, { Component } from 'react';
import {
View,
FlatList,
Text,
TouchableWithoutFeedback,
ListView,
ScrollView
} from 'react-native'
import { NavigationActions } from 'react-navigation';
import { Header, Card, CardSection } from '../common';
import Config from '../Config';
export default class Costco extends Component<Props> {
constructor(props) {
super(props);
this.state = {
stores: [],
selectedItem: {id: null},
};
}
componentWillMount() {
const obj = Config.costcoThree;
const costcoArr = Object.values(obj);
this.setState({
stores: costcoArr,
})
}
renderListOfStores() {
return <FlatList
data={this.state.stores}
renderItem={ ({item}) => this.singleStore(item)}
keyExtractor={(item) => item.id}
extraData={this.state.selectedItem} />
}
singleStore(item) {
console.log(this.state.selectedItem.id)
return item.id === this.state.selectedItem.id ?
<TouchableWithoutFeedback
onPress={() => this.selectStore(item)}
>
<View>
<Text>{item.branchName}</Text>
<Text>Opening Time {item.openingTime}</Text>
<Text>Closing Time {item.closingTime}</Text>
<Text>Address {item.dongAddKor}</Text>
</View>
</TouchableWithoutFeedback>
:
<TouchableWithoutFeedback>
<View>
<Text>{item.branchName}</Text>
<Text>Only showing second part</Text>
</View>
</TouchableWithoutFeedback>
}
selectStore(item) {
this.setState({selectedItem: item});
console.log('repssed');
}
render() {
return(
<ScrollView>
<Header headerText="Costco"/>
<Text>hello</Text>
{this.renderListOfStores()}
</ScrollView>
)
}
}
as a workaround you can have a state that maintain your selected item to expand(or something like another view) and then you can use some conditions to work for render your flat list data.
Consider the below code and let me know if you need some more clarification.
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,FlatList,TouchableNativeFeedback,
View
} from 'react-native';
export default class App extends Component<Props> {
constructor(props) {
super(props);
this.state = {
response: [],
selectedItem: {id: null},
};
}
userListLayout() {
const {response} = this.state;
return <FlatList data={response} renderItem={ ({item}) => this.singleUserLayout(item)} keyExtractor={(item) => item.email} extraData={this.state.selectedItem} />
}
singleUserLayout(item) {
return item.id == this.state.selectedItem.id ?
<TouchableNativeFeedback onPress={() => this.userSelected(item)}>
<View style={{flex:1, borderColor: 'black', borderWidth: 1}}>
<Text style={{padding: 10, fontSize: 25}}>{item.email}</Text>
<Text style={{padding: 10,fontSize: 20}}>{item.name}</Text>
</View>
</TouchableNativeFeedback>
: <TouchableNativeFeedback onPress={() => this.userSelected(item)}><Text style={{padding: 10,fontSize: 20}}>{item.email}</Text></TouchableNativeFeedback>
}
userSelected(item) {
console.log(item)
this.setState({selectedItem: item})
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then(data => data.json())
.then(response => this.setState({response}))
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>HI THERE</Text>
{this.userListLayout()}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});

How to populate a Flatlist from TextInput

I am trying to populate a FlatList row with the value coming from a TextInput.
Below you can find my current code.
import React, { Component } from 'react'
import { View, Text, TouchableOpacity, TextInput, StyleSheet,
StatusBar, FlatList } from 'react-native'
globalText = require('../styles/Texts.js');
globalColors = require('../styles/Colors.js');
class SearchInput extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
ingredients: ''
}
}
_handleIngredients = (text) => {
this.setState({ ingredients: text })
}
render(){
return (
<View style={styles.container}>
<StatusBar barStyle="dark-content"/>
<View>
<TextInput style={[globalText.btnFlatPrimary, styles.inputText]}
underlineColorAndroid='transparent'
placeholder='Add ingredients'
placeholderTextColor={globalColors.lightGrey}
autoCapitalize='sentences'
autoCorrect={false}
autoFocus={true}
onChangeText={this._handleIngredients}
keyboardShouldPersistTaps='handled'
/>
</View>
<FlatList
data={this.state.data}
renderItem={({text}) => (
<View style={styles.cell}>
<Text style={globalText.btnFlatPrimary}>{this.state.ingredients}</Text>
</View>
)}
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
paddingTop: 20,
backgroundColor: globalColors.white,
},
inputText: {
paddingLeft: 16,
paddingRight: 16,
height: 60
},
cell: {
height: 60,
paddingLeft: 16,
justifyContent: 'center',
}
});
export default SearchInput;
I am probably missing something but if I pre populate the data and the ingredients states, then FlatList display correctly with the entered values. What I'd like it to populate the Flalist with the TextInput
data: [{key:'a'}],
ingredients: 'tomato'
Flatlist will only re-render if the data property changes. If you want it to re-render based on other values, you would need to pass an extraData prop.
<FlatList
data={this.state.data}
extraData={this.state.ingredients} //here
renderItem={({text}) => (
<View style={styles.cell}>
<Text style={globalText.btnFlatPrimary}>{this.state.ingredients}</Text>
</View>
)}
/>
Read more here: https://facebook.github.io/react-native/docs/flatlist.html#extradata
change: onChangeText={this._handleIngredients}
to: onChangeText={(text) => this._handleIngredients(text)}
This is for preserving the scope of this.