i am using Flatlist from react-native and ListItem from react-native-elements,
i want to initially limit the number of list-items that are loaded on the screen.Otherwise it loads all the items that i have initially .
Suppose i have 300 list items but initially i only want to load 10 items ,instead of 300.
MY CODE:
import React, { Component } from 'react'
import {
FlatList
} from 'react-native'
import {Avatar,Tile,ListItem} from 'react-native-elements'
export default class Login extends Component{
constructor(props) {
super(props);
this.state = {
data:[],
dataSource: []
};
}
renderList(item,i){
return(
<View>
<ListItem
subtitle={
<Avatar
small
rounded
source={{uri: "https://s3.amazonaws.com/uifaces/faces/twitter/ladylexy/128.jpg"}}
/>
{<Text>{item.body}</Text>}
}
/>
<View>
)
}
render(){
return(
<View>
<List>
<FlatList
data={this.state.data}
keyExtractor={item => item.id}
renderItem ={({item,index}) => this.renderList(item,index)}
/>
</List>
</View>
)
}
}
Basically, what you need is to implement sort of pagination. You can do it by using onEndReached and onEndReachedThreshold(for more details look here) of FlatList to load more data when user reaches the end of list.
You can change your code like so:
import React, { Component } from 'react';
import { FlatList } from 'react-native';
import { Avatar, Tile, ListItem } from 'react-native-elements';
const initialData = [0,...,299]; //all 300. Usually you receive this from server or is stored as one batch somewhere
const ITEMS_PER_PAGE = 10; // what is the batch size you want to load.
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
data: [0,..., 9], // you can do something like initialData.slice(0, 10) to populate from initialData.
dataSource: [],
page: 1,
};
}
renderList(item, i) {
return (
<View>
<ListItem />
</View>
);
}
loadMore() {
const { page, data } = this.state;
const start = page*ITEMS_PER_PAGE;
const end = (page+1)*ITEMS_PER_PAGE-1;
const newData = initialData.slice(start, end); // here, we will receive next batch of the items
this.setState({data: [...data, ...newData]}); // here we are appending new batch to existing batch
}
render() {
return (
<View>
<FlatList
data={this.state.data}
keyExtractor={item => item.id}
renderItem={({ item, index }) => this.renderList(item, index)}
onEndReached={this.loadMore}
/>
</View>
);
}
}
Related
I have a component and import it in specific screen, in this screen i have a button when clicks i open modal contain component it's a "recorder" so after i record voices i want to take this voice and save them into Parent screen as a state or something!
in the recorder component, I save voices data into state! but how can i pass it to other parent screens!?
so how can I handle it?
here is shots
Parent Screen "after click add voice I show the modal"
Parent Screen
Here's a modal contain a recorder component
Modal
CODE
Component
" I pass data to PassDataToModal state inside componentDidMount "
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, TouchableOpacity, View} from 'react-native';
import {AudioRecorder, AudioUtils} from 'react-native-audio';
import Sound from 'react-native-sound';
import Icon from 'react-native-vector-icons/MaterialIcons';
class RecorderScreen extends Component {
state = {
PassDataToModal: null,
};
componentDidMount() {
AudioRecorder.requestAuthorization().then(isAuthorised => {
this.setState({hasPermission: isAuthorised});
AudioRecorder.onFinished = data => {
console.log('data', JSON.stringify(data));
this.setState({PassDataToModal: data});
};
});
}
render() {
return (
<View style={styles.container}>
<View style={styles.controls}>
{this._renderPlayButton(() => {
this._play();
})}
{this._renderRecordButton(this.state.recording)}
{this._renderStopButton('Stop', () => {
this._stop().then(() => this.setState({currentTime: 0}));
})}
</View>
<Text style={styles.progressText}>{this.state.currentTime}s</Text>
</View>
);
}
}
export default RecorderScreen;
Parent Screen
import Modal from 'react-native-modal';
import RecorderScreen from './Recorder';
class Order extends Component {
constructor(props) {
super(props);
this.state = {
isModalVisible: false,
};
}
toggleModal = () => {
this.setState({isModalVisible: !this.state.isModalVisible});
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity
onPress={this.toggleModal}
>
<Icon name="mic" color="#333" size={20} />
<Text style={{paddingHorizontal: 5}}>Add Voice</Text>
</TouchableOpacity>
<Modal
style={{margin: 0}}
isVisible={this.state.isModalVisible}
>
<View>
<TouchableOpacity onPress={this.toggleModal}>
<Icon name="close" color="#000" size={25} />
</TouchableOpacity>
<RecorderScreen /> // Component
</View>
</View>
)
}
}
In your parent component pass a function to your RecorderScreen component that will send the necessary data up. Docs on lifting state up.
So in your parent you'd have something like:
setData = (data) => {
// Set this to whatever you need it to be named
this.setState({childData: data});
}
Then pass the function as a prop:
<RecorderScreen setData={this.setData} />
And finally, call it in the child however needed (If I'm following the code something like this):
componentDidMount() {
AudioRecorder.requestAuthorization().then(isAuthorised => {
this.setState({hasPermission: isAuthorised});
AudioRecorder.onFinished = data => {
this.props.setData(data);
};
});
}
Then your parent component will have access to the child's data that you have lifted up.
My team is working on a tutoring app where students send in requests from the student side to the tutor side. We are able to reference firebase for out data and see it in the console. But we are not able to display on the page.
This is the tutor side code here:
import React from 'react';
import { FlatList, Text, StyleSheet, View } from 'react-native';
import firebaseRef from './Firebase';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = ({
sessions: []
});
}
componentDidMount(){
const { uid } = firebaseAuth.currentUser
firebaseRef.database().ref('Sessions/' + uid).on('value', function (snapshot) {
sessions = snapshot.val()
this.setState({
sessions: sessions,
sessions,
});
})
}
getSessionsRef = () => {
return firebaseRef.database().ref('sessions')
}
render(){
const {sessions} = this.state
return(
<View style={styles.container}>
<FlatList>
<Text>{sessions}</Text>
</FlatList>
</View>
)
}
}
const styles = StyleSheet.create({
container:{
flex: 1,
justifyContent:'center',
padding:-1.5
}
});
Something like this:
<FlatList
data={sessions}
keyExtractor={(item, index) => item.id}
renderItem={({item}) => (
<Text>{item}</Text>
)}
/>
I'm trying to figure out why Match and History aren't showing up whenever I slide my <Drawer/>. I've looked around a lot throughout the web and SO but can't find anything pertaining to this.
Here's SideMenu.js file:
import React, {Component} from 'react';
import { Text, View} from 'react-native';
import {List, ListItem, Header} from 'react-native-elements';
import Container from "native-base/src/theme/components/Container";
export default class SideMenu extends Component {
constructor(props) {
super(props);
}
render() {
let list = [{
title: "Match",
onPress: () => {
this.props.navigator.replace("Match")
}
}, { // 2nd menu item below
title: "History",
onPress: () => {
this.props.navigator.replace("History")
}
}];
return(
<Container theme={this.props.theme}>
<Header/>
<View>
<List dataArray={list} renderRow={(item) =>
<ListItem button onPress={item.onPress.bind(this)}>
<Text>{item.title}</Text>
</ListItem>
}/>
</View>
</Container>
);
}
}
Here's AppContainer.js file:
import React, {Component} from 'react';
import {Navigator} from 'react-native-deprecated-custom-components';
import Drawer from "react-native-drawer-menu";
import SideMenu from './components/sideMenu';
export default class AppContainer extends Component {
constructor(props) {
super(props);
this.state = {
toggled: false,
store: {}, // holds data stores
theme: null
}
}
toggleDrawer() {
this.state.toggled ? this._drawer.close() : this._drawer.open();
}
openDrawer() {
this.setState({toggled: true});
}
closeDrawer() {
this.setState({toggled: false});
}
renderScene(route, navigator) { // current route you want to change to, instance of the navigator
switch(route) {
default: {
return null;
}
}
}
// handles how our scenes are brought into view
configureScene(route, routeStack) {
return Navigator.SceneConfigs.PushFromLeft; // pushes new scene from RHS
}
render() {
return(
<Drawer
ref = {(ref) => this._drawer = ref}
type = 'default' // controls how menu appears on screen, pushes content to the side
content = {<SideMenu navigator={this._navigator} theme={this.state.theme}
/>}
onClose={this.closeDrawer.bind(this)}
onOpen={this.openDrawer.bind(this)}
openDrawerOffset={0.9}
>
<Navigator
ref={(ref) => this._navigator = ref}
configureScene={this.configureScene.bind(this)}
renderScene={this.renderScene.bind(this)}
/>
</Drawer>
);
}
}
First of all there's no such property as dataArray in ListView component. You need to create data source first and pass it to dataSource property. Look at the example in the DOCUMENTATION
Looking at the Lists API for react-native-elements https://react-native-training.github.io/react-native-elements/API/lists/
Examples using ListItem are using title prop for setting the title. Maybe try returning this instead from SideMenu render
return(
<Container theme={this.props.theme}>
<Header/>
<View>
<List>
{
list.map((item, i) => (
<ListItem onPress={item.onPress} key={i} title={item.title}/>
))
}
</List>
</View>
</Container>
);
React native only loads the first page properly. The items are coming from an array. Filling the array with works, but loading the from a custom component doesn't. The issue only happens when another custom component is rendered.
//Main page render
render() {
return (
<ContainerView disableBackgroundButton={true} onLayout={this._onLayoutDidChange}>
<Image
source={require('../../img/barbershop_request.png')}
style={styles.backgroundImage}>
<View style={styles.overlay}></View>
</Image>
<ScrollView
ref="scrollView"
showsVerticalScrollIndicator={false}>
<Swiper
loop={false}
showsPagination={false}
height={Global.constants.HEIGHT * 1.34}>
{this.createBarberItems()}
</Swiper>
</ScrollView>
</ContainerView>
)
}
createBarberItems() {
...
for (index in barbers) {
...
let barberItem = <BarberItemView />
barberItems.push(barberItem)
}
// this works fine
// let testItems = [];
// testItems.push(<Text> here1</Text>)
// testItems.push(<Text>here2</Text>)
//return testItems;
return barberItems;
}
//BarberItemView Render
render() {
return (
<Text>Barber Item View</Text>
)
}
try to surround your BarberItemView with View component
render() {
return (
<View>
<Text>Barber Item View</Text>
<View>
)
}
don't forget to import View component from react-native lib in your BarberItemView
import React from 'react';
import {Text,
View } from 'react-native';
This is my main app.js looks like
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
ScrollView
} from 'react-native';
import BarberItemView from './BarberItemView';
import Swiper from 'react-native-swiper';
export default class ReactSwiper extends Component {
render() {
return (
// you can replace this view component with your own custom component
<View style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#9DD6EB'
}}>
{/* <Image
source={require('./barbershop_request.png')}
style={styles.backgroundImage}>
<View style={styles.overlay}></View>
</Image> */}
<ScrollView
ref="scrollView"
showsVerticalScrollIndicator={true}>
<Swiper
loop={true}
showsPagination={true}>
{this.createBarberItems()}
</Swiper>
</ScrollView>
</View>
)
}
createBarberItems() {
//since i don't know how your data looks like, i just use some dummy
let barbers = [1, 2, 3, 4, 5]; // your barber array
let barberItems = []; // your barber items
for (index in barbers) {
let barberItem = <BarberItemView />
barberItems.push(barberItem)
}
return barberItems;
// this works fine
// let testItems = [];
// testItems.push(<Text> here1</Text>)
// testItems.push(<Text>here2</Text>)
// return testItems;
}
}
I'm trying to use the React Native <ListView /> component with the <List /> and <ListItem /> component from React Native Elements but the <ListItem /> component isn't displaying. Not entirely sure why. Shouldn't my renderRow function be running for every object in my array and returning <Listitem />? My data is coming in fine.
Please let me know what I'm doing wrong. Thanks! Code is below
import React, { PropTypes, Component } from 'react'
import { View, Text, ListView, StyleSheet } from 'react-native'
import { connect } from 'react-redux'
import { List, ListItem } from 'react-native-elements'
import { getMakeData } from '~/redux/modules/data'
class Make extends Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
makeData: PropTypes.array.isRequired
}
constructor (props) {
super(props)
this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2 })
this.state = {
dataSource: this.ds.cloneWithRows(this.props.makeData)
}
}
componentDidMount () {
this.props.dispatch(getMakeData())
}
renderRow = (item) => {
return (
<ListItem
key={item.id}
title={item.name}
/>
)
}
render () {
console.log(this.props.makeData)
return (
<List style={{flex: 1}}>
<ListView
renderRow={item => this.renderRow(item)}
dataSource={this.state.dataSource}
/>
</List>
)
}
}
function mapStateToProps ({data}) {
return {
makeData: data.makeData
}
}
export default connect(mapStateToProps)(Make)
const styles = StyleSheet.create({
})
It looks like your issue is you are not using renderRow correctly. Based on your description, makeData is an array of objects, so in your render function, you call ListView with that array, but renderRow should only render single row and should be passed in the data for each row. So, change your renderRow and render function like below
renderRow (item) {
return (
<ListItem
key={item.id}
title={item.name}
/>
)
}
render () {
return (
<List style={{flex: 1}}>
<ListView
renderRow={(item) => this.renderRow(item)}
dataSource={this.props.makeData}
/>
</List>
)
}
What is happening now is that you are telling renderRow here is the object you should be using.
What you had before is you are trying to render ListItem using the array makeData, where you should be using a single object to render the row.
fix bug:
renderRow={this.renderRowt} -> renderRow={this.renderRow.bind(this)}
refactor code
function mapStateToProps ({ data }) {
return {
makeData: data.makeData
}
}
->
1-
function mapStateToProps ({ data:{makeData} }) {
return {
makeData,
}
}
export default connect(mapStateToProps)(Make)
2-
const mapStateToProps = ({ data:{makeData} }) => makeData
export default connect(mapStateToProps)(Make)
3-
export default connect(({ data:{makeData} }) => makeData)(Make)