React-native flatlist not rendering? - javascript

My ReactNative FlatList is not rendering with this simple implementation.
<FlatList style={{flex:1, backgroundColor:'red'}}
data = {this.state.users}
keyExtractor={item => item.key.toString()}
renderItem={({item}) => {
return (
<ChatUserCard key={item.uid} username={item.username} />
)
}}
/>
ChatUserCard
<View style={styles.cardStyle}>
<Text style={styles.itemStyle}>{this.props.username}</Text>
<Button style={styles.buttonStyle}
title='Chat'
onPress={this.startChat} />
</View>

Try add comments to the view below the flatlist and remove flex 1 from the styles on the flatlist. Try that to check if it is related with the styles

I'm thinking what's going on is that you've not wrapped your FlatList in a View that has flex: 1 set. Also, you can probably use your uid as your key, rather than setting a key in your object data
Demo
https://snack.expo.io/#anonymoussb/so53688423
import * as React from 'react';
import { Text, View, StyleSheet, Button, FlatList } from 'react-native';
class ChatUserCard extends React.Component {
render() {
return (
<View style={styles.cardStyle}>
<Text style={styles.itemStyle}>{this.props.username}</Text>
<Button style={styles.buttonStyle}
title='Chat'
onPress={this.startChat} />
</View>
)
}
}
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
users: [
{ key: 123, uid: 123, username: 'taco' },
{ key: 456, uid: 456, username: 'cat' }
]
}
}
render() {
return (
<View style={styles.container}>
<FlatList style={{flex:1, backgroundColor:'red'}}
data = {this.state.users}
keyExtractor={item => item.key.toString()}
renderItem={({item}) => {
return (
<ChatUserCard key={item.uid} username={item.username} />
)
}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
});

Related

Add two button for each item in flatlist

Actually i'm working for a school project in react native and i want to know if it's possible to add two buttons into flatlist using react-native.
export class ItineraryScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
data:[
{key: 'PKRX'},
{key: 'UXUA'},
{key: 'PGRF'},
]
};
}
render() {
return (
<ScrollView>
<FlatList
data={this.state.data}
renderItem={({item}) => <Text style={styles.item}>{item.key}</Text>}
/>
</ScrollView>
);
}
could you give some advices to implement this feature please?
Best regards,
Imad.
Here is an example of how yu could do it (Repro on Snack Expo) :
import * as React from 'react';
import { Text, View, StyleSheet , FlatList, Button} from 'react-native';
export default function App() {
const data = [
{key: 'PKRX'},
{key: 'UXUA'},
{key: 'PGRF'},
];
return (
<View>
<FlatList data={data} renderItem={({item}) => <Item item={item} /> } />
</View>
);
}
const Item = ({item}) => {
return (
<View style={{flex: 1, flexDirection: 'row', alignItems: 'center'}}>
<Text>{item.key}</Text>
<View style={{flex:1, flexDirection: 'row-reverse'}}>
<Butto title='Button 1' onPress={() => {}} />
<Button title='Button 2' onPress={() => {}} />
</View>
</View>
)
}

How to add input fields into a list in React Native?

I'm a beginner in React Native ans struggling with adding Input (Search bars) into a list by clicking a button. Here's my code:
import React, { useState } from "react";
import {
View,
Text,
Button,
FlatList
} from 'react-native'
import InputDemo from '../components/InputDemo'
const INCREMENT = 1;
class AddInputDemo extends React.Component{
constructor(props){
super(props);
this.state={
counter: 0,
numOfInput: [0]
}
this.addInput = this.addInput.bind(this)
}
addInput(){
this.setState((state) => ({
counter: state.counter + INCREMENT,
numOfInput: [...state.numOfInput, state.counter]
}))
console.log(this.state.counter);
console.log(this.state.numOfInput);
}
render(){
return(
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<FlatList
data={this.state.numOfInput}
keyExtractor={(item, index) => item.id}
renderItem={itemData => {
<InputDemo/>
}}
/>
<Button title='Add a location' onPress={this.addInput} />
</View>
);
}
}
export default AddInputDemo;
Here's the InputDemo file:
import * as React from 'react'
import {
View,
Text,
TextInput,
Button
} from 'react-native'
const InputDemo = props => {
return(
<View style={{borderColor: 'black', borderWidth: 1}}>
<TextInput
placeholder='Search'
/>
</View>
)
}
export default InputDemo;
It's weird since I use this same logic with state in Functional Component. It works. But when applying to a Class Component, it does not show anything when I click that button.
THANKS FOR ANY HELP !!!
EDIT
I tried to use extraData:
<FlatList
extraData={this.state.numOfInput}
keyExtractor={(item, index) => item.id}
renderItem={itemData => {
<InputDemo
id={itemData.item.id}
/>
}}
/>
And created an id for each InputDemo:
const InputDemo = props => {
return(
<View key={props.id} style={{borderColor: 'black', borderWidth: 1}}>
<TextInput
placeholder='Search'
/>
</View>
)
}
But it still does not work
Please help !!!
FlatList data attribute takes prop as Array. Documentation is your bestfriend.
Everything goes more or less like below, not tested but closer to what you want, I hope.
import React, { useState } from "react";
import {
View,
Text,
Button,
FlatList
} from 'react-native'
import InputDemo from '../components/InputDemo'
const INCREMENT = 1;
class AddInputDemo extends React.Component{
constructor(props){
super(props);
this.state={
counter: 0,
numOfInput: [0],
item:'',
searchArray:[],
}
this.addInput = this.addInput.bind(this)
}
addInput(){
this.setState((state) => ({
counter: state.counter +=1,
searchArray:[...this.state.searchArray, this.state.item] //appends search item to search array
numOfInput: [...state.numOfInput, state.counter] //don't know why you need this
}))
}
render(){
return(
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<InputDemo search={(searchItem)=>this.setState({item:searchItem})}/>
<FlatList
data={this.state.searchArray}
keyExtractor={(item, index) => item.id}
renderItem={itemData => {
<Text>{itemData}</Text>
}}
/>
<Button title='Add a location' onPress={this.addInput} />
</View>
);
}
}
export default AddInputDemo;
And Input Demo
import * as React from 'react'
import {
View,
TextInput
} from 'react-native'
const InputDemo = props => {
const onChangeText = (item) => {
props.search(item); //add search item to state of "class AddInputDemo" using props
}
return(
<View style={{borderColor: 'black', borderWidth: 1}}>
<TextInput
placeholder='Search'
onChangeText={text => onChangeText(text)}
/>
</View>
)
}
export default InputDemo;
EDIT 2
Hi guys, I know where the error is now. It's not about the data or extraData. The solution is we have to wrap around the <InputDemo/> with a return statement. It works well then. Thank you all for the helpful answers.
You should pass extraData
A marker property for telling the list to re-render (since it implements PureComponent). If any of your renderItem, Header, Footer, etc. functions depend on anything outside of the data prop, stick it here and treat it immutably.
<FlatList
data={this.state.numOfInput}
extraData={counter}
keyExtractor={(item, index) => item.id}
renderItem={itemData => (
<InputDemo/>
)}
/>
Edit:
You also have a huge problem, your data don't have .id prop and keyExtractor probably isn't working.
You could change it to
keyExtractor={(item, index) => index.toString()}
But this still isn't good, try adding unique id prop to each item.

there is a way to fix "Warning: Each child in a list should have a unique "key"?

Is there a way to fix this warning?
Warning: Each child in a list should have a unique "key
I got this warning every time and don't understand how to fix it.
I try to fix it but i realize that something wrong in my way .
hope to understand whats wrong because its so annoying.
import React, { Component } from 'react';
import { View, Text, StyleSheet, ActivityIndicator, Platform, FlatList, Dimensions, Image } from 'react-native';
import { HeaderButtons, Item } from 'react-navigation-header-buttons'
import HeaderButton from '../components/HeaderButton';
import axios from 'axios';
const { width, height } = Dimensions.get('window');
export default class PlacesListScreen extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: [] };
}
componentDidMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(res => {
this.setState({
isLoading: false,
data: res.data,
})
console.log(res.data);
})
}
renderItem(item) {
const { title, artist } = item.item;
return (
<View style={styles.itemView}>
<View style={styles.imgContainer}>
{/* <Image style={styles.imageStyle}
source={{ uri: image }}
/> */}
</View>
<View style={styles.itemInfo}>
<Text style={styles.name}>
{title+ ' ' + artist}
</Text>
<Text style={styles.vertical} numberOfLines={1}>{title} |</Text>
</View>
</View>
);
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<Text style={{ alignSelf: 'center', fontWeight: 'bold', fontSize: 20 }}>loading...</Text>
<ActivityIndicator />
</View>
)
}
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this.renderItem.bind(this)}
keyExtractor={item => item.id}
/>
</View>
);
}
}
Hope that you understand my problem and how can I fix it.
the example code above shows my try to get some data from API, but it returns a warning every time about
each child in a list should have a unique "key".
console.log the key of each item. It may be possible u have the same id for some items?

React-native how to use a state value in another javasript file

I want to use a value, from the file Step3.js in Step4.js, the value can change after user input in Step3. But how can I use this value in Step4?
I have tried some things, but I guess I miss the point here, so hopefully somebody can help me out with this.
This is my code:
App.js:
import React, { Component } from 'react'
import { AppRegistry, StyleSheet, View, Text } from 'react-native'
import { ViewPager } from 'rn-viewpager'
import StepIndicator from 'react-native-step-indicator'
import Step1 from "./Step1";
import Step2 from "./Step2";
import Step3 from "./Step3";
import Step4 from "./Step4";
const PAGES = [{id: 1, page: <Step1/>},{id: 2, page: <Step2/>}, {id: 3, page: <Step3/>}, {id: 4, page: <Step4/>}];
const firstIndicatorStyles = {
stepIndicatorSize: 30,
currentStepIndicatorSize: 40,
separatorStrokeWidth: 5,
currentStepStrokeWidth: 3,
separatorFinishedColor: '#4aae4f',
separatorUnFinishedColor: '#a4d4a5',
stepIndicatorFinishedColor: '#4aae4f',
stepIndicatorUnFinishedColor: '#a4d4a5',
stepIndicatorCurrentColor: '#ffffff',
stepIndicatorLabelFontSize: 15,
currentStepIndicatorLabelFontSize: 15,
stepIndicatorLabelCurrentColor: '#000000',
stepIndicatorLabelFinishedColor: '#ffffff',
stepIndicatorLabelUnFinishedColor: 'rgba(255,255,255,0.5)',
labelColor: '#666666',
labelSize: 12,
currentStepLabelColor: '#4aae4f'
};
export default class App extends Component {
constructor (props) {
super(props);
this.state = {
currentPosition: 0,
stepCount: 4,
}
}
componentWillReceiveProps (nextProps, nextState) {
if (nextState.currentPosition != this.state.currentPosition) {
if (this.viewPager) {
this.viewPager.setPage(nextState.currentPosition)
}
}
}
render () {
return (
<View style={styles.container}>
<ViewPager
style={{ flexGrow: 1 }}
ref={viewPager => {
this.viewPager = viewPager
}}
onPageSelected={page => {
this.setState({ currentPosition: page.position })
}}
>
{PAGES.map(page => this.renderViewPagerPage(page))}
</ViewPager>
<View style={styles.stepIndicator}>
<StepIndicator
customStyles={firstIndicatorStyles}
currentPosition={this.state.currentPosition}
stepCount={this.state.stepCount}
labels={['Kleur', 'Vorm', 'Moeite', 'Overzicht']}
/>
</View>
</View>
)
}
renderViewPagerPage = (data) => {
console.log(data);
console.log(this.state.currentPosition);
return (
<View key={data.id}>
{data.page}
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ffffff'
},
stepIndicator: {
marginVertical: 20
},
});
Step3.js:
export function getSelected3() {
return this.state.selected;
}
class Step3 extends Component {
constructor(props){
super(props);
this.state = {
happy: {
"id" : "1",
"name" : "happy",
"src" : require('../../assets/images/makkelijk.png')
},
normal: {
"id" : "2",
"name" : "normal",
"src" : require('../../assets/images/gemiddeld.png'),
},
sad: {
"id" : "3",
"name" : "sad",
"src" : require('../../assets/images/moeilijk.png'),
},
selected: {
"id" : "4",
"name" : "",
"src" : require('../../assets/images/moeilijk.png'),
},
};
}
onPress = (item) => {
this.state.selected.name = item.name;
this.state.selected.src = item.src;
alert(this.state.selected.name);
};
render() {
return (
<View style={styles.container}>
<View style={[styles.box]}>
<TouchableHighlight onPress={() => this.onPress(this.state.happy)}>
<Image
style={styles.image}
source={this.state.happy.src}
/>
</TouchableHighlight>
</View>
<View style={[styles.box]}>
<TouchableHighlight onPress={() => this.onPress(this.state.normal)}>
<Image
style={styles.image}
source={this.state.normal.src}
/>
</TouchableHighlight>
</View>
<View style={[styles.box]}>
<TouchableHighlight onPress={() => this.onPress(this.state.sad)}>
<Image
style={styles.image}
source={this.state.sad.src}
/>
</TouchableHighlight>
</View>
</View>
)
}
}
So I want to use the date from the state in Step3 selected into Step4.js, How can I Do this?
Step4.js:
class Step4 extends Component {
constructor(props) {
super(props);
this.state = {
value3: {
"id": "3",
"name" : "",
"src" : "",
},
};
}
render() {
let test = getSelected3();
this.state.value3.src = value3.src;
return (
<View style={styles.container}>
<View style={[styles.box]}>
<TouchableHighlight>
<Image
style={styles.image}
source={this.state.value3.src}
/>
</TouchableHighlight>
</View>
<View style={[styles.box]}>
<TouchableHighlight>
<Image
style={styles.image}
source={this.state.value3.src}
/>
</TouchableHighlight>
</View>
<View style={[styles.box]}>
<TouchableHighlight>
<Image
style={styles.image}
source={this.state.value3.src}
/>
</TouchableHighlight>
</View>
</View>
)
}
Suggest you to make Step3 and Step4 components stateless which will receive only props and create a component Stepper which will render both Step3 and Step4. Stepper component will do all the state manipulations.
class Stepper extents Component {
render() {
const { state1, state2, state3, state4, onPress } = this.state;
return [
<Step3 state1={state1} state3={state3} onPress={onPress} />,
<Step4 state2={state2} state4={state4} />
];
}
}
And Step3 would look like this:
const Step3 = ({ state1, state2, onPress }) => {
return (<TouchableHighlight onPress={onPress}></TouchableHighlight);
};
Hope you get the idea.
Copy pasting my answer from a similar question
I usually create a global.js containing:
module.exports = {
step3State: null,
};
And get the value of the state on the screen
render() {
GLOBAL.step3State = this;
//enter code here
}
Now you can use it anywhere like so:
GLOBAL.step3State.setState({
var: value
});
or
Global.step3State.state.value

React Native FlatList not working with constructed data

Works:
<FlatList
data={['0', '1', '2', '3', '4']}
renderItem={({ item }) => (
<Button title={item} />
)}
/>
Doesn't work (nothing rendered):
<FlatList
data={[...Array(5).keys()].map(String)}
renderItem={({ item }) => (
<Button title={item} />
)}
/>
What could possibly be the cause?
Its actually working, check out the demo below
https://snack.expo.io/H1elODwPb
And the code
import React, { Component } from 'react';
import { View, StyleSheet,FlatList,Button } from 'react-native';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<FlatList
data={[...Array(5).keys()].map(String)}
renderItem={({ item }) => (
<Button title={item} />
)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ecf0f1',
},
});

Categories

Resources