React Native FlatList not working with constructed data - javascript

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',
},
});

Related

Converting React-Native-Draggable-View from Class to Hooks

I am attempting to write some code using React-Native-Draggable-View but the example that has it the way I want is written in "class" form, while I write everything in "Hooks/Functional" form. Here is the original part of the code written in the class format. When I try to convert it myself I am generate an error.
import React, { useState, useEffect, Component }from "react";
import Drawer from 'react-native-draggable-view'
import CheckScreen from './CheckScreen'
import ListScreen from './ListScreen'
function RunningScreen({navigation}) {
...
return(
...
<Drawer
initialDrawerSize={0.09}
renderContainerView={() => { <View style = {{flex: 1, backgroundColor: 'red'}}/> }}
renderDrawerView={() => { <View style = {{flex: 1, backgroundColor: 'red'}}/> }}
renderInitDrawerView={() => {
<View style = {{backgroundColor: '#fff', height: height*0.2}}>
<StatusBar hidden = {true}/>
<StatusBar hidden = {true}/>
</View>
)}
/>
)
}
...
export {RunningScreen}
Try below code
import React from 'react';
import {Dimensions, StatusBar, View} from 'react-native';
import Drawer from 'react-native-draggable-view';
const {height} = Dimensions.get('window');
function RunningScreen({navigation}) {
return (
<Drawer
initialDrawerSize={0.09}
renderContainerView={() => (
<View style={{flex: 1, backgroundColor: 'red'}} />
)}
renderDrawerView={() => (
<View style={{flex: 1, backgroundColor: 'red'}} />
)}
renderInitDrawerView={() => (
<View style={{backgroundColor: '#fff', height: height * 0.2}}>
<StatusBar hidden={true} />
</View>
)}
/>
);
}
export {RunningScreen};

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.

React-native flatlist not rendering?

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
},
});

Navigate Issue From a ListView

I have 2 listview in my homepage (TodoDetail.js and TodoDetailChecked.js) and there is TouchableOpacity's in this listview's rows.. When I click this TouchableOpacity, I want to go to Profile.js page.
But the problem is when I click, it can not find props.navigation.navigate.
I tried to catch logs in componentDidMount but nothing about navigate.
componentDidMount() {
console.log(this.props);
}
Please help me...
Here is the code;
TodoDetail.js
import React, { Component } from 'react';
import { Card, Icon } from 'react-native-elements';
// import Checkbox from '../components/Checkbox';
import { Text, View, TouchableOpacity } from 'react-native';
import * as firebase from 'firebase';
import {
Menu,
MenuOptions,
MenuOption,
MenuTrigger,
} from 'react-native-popup-menu';
class TodoDetail extends Component {
componentDidMount() {
console.log(this.props.navigation.navigate('TodoDetail'));
}
clickText() {
const { todo } = this.props.todos;
// const { navigate } = this.props.navigation;
return (
<TouchableOpacity onPress={this.seeDetail.bind(this)} >
<Text numberOfLines={1}> {todo} </Text>
</TouchableOpacity>
);
}
seeDetail() {
const { navigate } = this.props.navigation;
navigate("Profile", { name: "Jane" });
console.log('click');
}
render() {
//Serverdan çekilenler
const uid = this.props.todos.uid;
const success = this.props.todos.success;
//Tarih olayları
const date = new Date();
const day = date.getDate();
const tomorrow = day + 1;
const year = date.getFullYear();
const month = date.getMonth();
//Style tanımlama
const { container, iconContainer, subContainer } = styles;
if (success === 0) {
return (
<Card>
<View style={container}>
<View style={iconContainer}>
<TouchableOpacity onPress={() => firebase.database().ref(`todos/personal/${uid}/success`).set(1)} >
<Icon name='check-box-outline-blank' />
</TouchableOpacity>
<View style={subContainer}>
{this.clickText()}
</View>
<View style={iconContainer}>
<Menu>
<MenuTrigger>
<Icon name='keyboard-arrow-down' />
</MenuTrigger>
<MenuOptions>
<MenuOption onSelect={() => firebase.database().ref(`todos/personal/${uid}/date`).set({ day, year, month })} >
<Text style={{ color: 'black' }} > Son Tarihi Bugün </Text>
</MenuOption>
<MenuOption onSelect={() => firebase.database().ref(`todos/personal/${uid}/date`).set({ day: tomorrow, year, month })} >
<Text style={{ color: 'black' }} > Son Tarihi Yarın </Text>
</MenuOption>
<MenuOption onSelect={() => firebase.database().ref(`todos/personal/${uid}/date`).remove()} >
<Text style={{ color: 'black' }} > Son Tarihi Kaldır </Text>
</MenuOption>
<MenuOption onSelect={() => firebase.database().ref(`todos/personal/${uid}`).remove()} >
<Text style={{ color: 'red' }} > Yapılacak İşi Sil </Text>
</MenuOption>
</MenuOptions>
</Menu>
</View>
</View>
</View>
</Card>
);
} else
if (success === 1) {
return (
null
);
}
}
}
Todolist.js
createDataSource({ studentsArray }) {
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.dataSource = ds.cloneWithRows(studentsArray.reverse());
}
changeScreen() {
this.setState({ screenSize: false });
}
changeScreenBack() {
this.setState({ screenSize: true });
}
renderRow(todos) {
return <TodoDetail todos={todos} />;
}
renderRow2(todos) {
return <TodoDetailChecked todos={todos} />;
}
render() {
// const { navigate } = this.props.navigation;
const { container, inputContainer, inputText } = styles;
if (!this.state.screenSize) {
return (
<View style={container} >
<View style={inputContainer} >
<Icon name={'add'} />
<TextInput
style={inputText}
underlineColorAndroid='transparent'
placeholder="Yapılacak iş ekle..."
placeholderTextColor="#FFFFFF"
value={this.props.todo}
onChangeText={todo => this.props.todoChanged(todo)}
/>
<Button
onPress={this.addToDo.bind(this)}
title="Ekle"
color="#841584"
accessibilityLabel="Learn more about this purple button"
/>
</View>
<View style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<ListView
enableEmptySections
dataSource={this.dataSource}
renderRow={this.renderRow}
/>
</View>
<View style={{ flex: 1 }}>
<View style={{ height: 1, backgroundColor: 'gray' }} />
<ListView
enableEmptySections
dataSource={this.dataSource}
renderRow={this.renderRow2}
/>
</View>
</View>
<Button
onPress={this.changeScreenBack.bind(this)}
title="Tamamlananları Gizle"
color="#841584"
/>
</View>
);
} else
if (this.state.screenSize) {
return (
<View style={container} >
<View style={inputContainer} >
<Icon name={'add'} />
<TextInput
style={inputText}
underlineColorAndroid='transparent'
placeholder="Yapılacak iş ekle..."
placeholderTextColor="#FFFFFF"
value={this.props.todo}
onChangeText={todo => this.props.todoChanged(todo)}
/>
<Button
onPress={this.addToDo.bind(this)}
title="Ekle"
color="#841584"
/>
</View>
<View style={{ flex: 1 }}>
<ListView
enableEmptySections
dataSource={this.dataSource}
renderRow={this.renderRow}
/>
<Button
onPress={this.changeScreen.bind(this)}
title="Tamamlananları Göster"
color="#841584"
/>
</View>
</View>
);
}
}
}
Router.js
import { StackNavigator } from 'react-navigation';
import Todolist from './src/Todolist';
import Profile from './src/Profile';
import TodoDetail from './components/TodoDetail';
import TodoDetailChecked from './components/TodoDetailChecked';
import TodoPage from './components/TodoPage';
const Router = StackNavigator({
Todolist: { screen: Todolist },
TodoDetail: { screen: TodoDetail },
Profile: { screen: Profile },
TodoDetailChecked: { screen: TodoDetailChecked },
TodoPage: { screen: TodoPage }
});
export default Router;
This problem about parent child problem.
Let's quotes from documentation:
It's important to note that this only happens if the screen is
rendered as a route by React Navigation (for example, in response to
this.props.navigation.navigate). For example, if we render
DetailsScreen as a child of HomeScreen, then DetailsScreen won't be
provided with the navigation prop, and when you press the
"Go to Details... again" button on the Home screen, the app will throw one of
the quintessential JavaScript exceptions "undefined is not an object".
To fix your problem is pass this.props.navigation to child component from higher component.
Let's do example:
App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import MyView from './MyView';
import { StackNavigator } from 'react-navigation';
import DetailsScreen from './DetailsScreen';
class App extends React.Component {
render() {
return (
<View style={styles.container}>
<MyView navigation={this.props.navigation} />
<Text>Open up App.js to start working on your app!</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default StackNavigator({
Home: {
screen: App,
},
Details: {
screen: DetailsScreen,
}
});
MyView.js
import React from 'react';
import { StyleSheet, Text, ListView } from 'react-native';
import TodoDetail from './TodoDetail';
export default class MyView extends React.Component {
constructor() {
super();
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.state = {
dataSource: ds.cloneWithRows(['todo 1', 'todo 2']),
};
}
renderRow(todos) {
return <TodoDetail todos={todos} navigation={this.props.navigation} />;
}
render() {
return (
<ListView
enableEmptySections
dataSource={this.state.dataSource}
renderRow={(rowData) => this.renderRow(rowData)}
/>
);
}
}
TodoDetail.js
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
export default class TodoDetail extends React.Component {
componentDidMount() {
// console.log(this.props.navigation.navigate('Details'));
}
render() {
return (
<View>
<Text>Todo detail</Text>
<Text>{this.props.todos}</Text>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details', { itemDetail: this.props.todos })}
/>
</View>
);
}
}
DetailsScreen.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default class DetailsScreen extends React.Component {
componentDidMount() {
console.log(this.props.navigation);
}
render() {
const { params } = this.props.navigation.state;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Text>{ params.itemDetail }</Text>
</View>
);
}
}
so in here, you need to pass navigation={this.props.navigation} every child render. If you see MyView component pass navigation props <MyView navigation={this.props.navigation} />.
And inside of it <TodoDetail todos={todos} navigation={this.props.navigation} />, last TodoDetail will available this.props.navigation to access this.props.navigation.navigate.

Categories

Resources