Related
I have a search bar in my React Native app, without context implementation the list displayed properly. But when I implemented Context, the list was not displaying again, only the search bar was displaying, and when I type on the search bar I get this error message; ERROR TypeError: item.indexOf is not a function. (In 'item.indexOf(str)', 'item.indexOf' is undefined)
I know am missing something, but I don't know where am missing it. Please I need help to solve this issue. Below is my code:
//....
//....
import songs from '../../SongData';
import styles from './styles';
const data = [songs];
const ListContext = React.createContext({
list: [data],
setList: () => {}
});
export const ListProvider = ({ children }) => {
const [list, setList] = useState(data);
return (
<ListContext.Provider value={{list, setList}}>
{children}
</ListContext.Provider>
);
};
const Item = ({ item }) => {
return (
<View>
<Text>{item.name}</Text>
</View>
);
};
const Playerlist = () => {
const [isDisabled, setisDisabled] = useState(false);
const [loading, setLoading] = useState(false);
const [isPlayed, setIsPlayed] = useState(false);
const [data, setData] = useState(songs);
//....
//.....
const renderHeader = () => {
const [text, setText] = useState("");
const listContext = useContext(ListContext);
const updateQuery = (str) => {
listContext.setList(data.filter((item) => item.indexOf(str) > -1));
setText(str);
};
return (
<View
style={{
backgroundColor: '#fff',
padding: 10,
marginVertical: 10,
borderRadius: 20
}}
>
<TextInput
autoCapitalize="none"
autoCorrect={false}
clearButtonMode="always"
value={text}
onChangeText={updateQuery}
placeholder="Search songs"
style={{ backgroundColor: '#fff', paddingHorizontal: 20 }}
/>
</View>
)
};
const renderItem = ({ item, index }) => (
<ScrollView style={{flex: 1}}>
<View style={styles.item}>
<Avatar
source={{ uri: item.picture }}
style={{ marginRight: 16 }}
size='giant'
/>
<Text style={styles.title} category='s1'> {item.title} </Text>
</View>
<Text
style={{
color: '#444',
fontSize: 11,
marginLeft: 112,
marginVertical: -20,
bottom: 27
}}
category='s1'
>{item.ArtistName}
</Text>
<Text
style={{
color: '#999',
marginLeft: 110,
marginVertical: -20,
top: 10
}}
category='s1'
>Genre: {item.genre}
</Text>
<View style={{flexDirection: 'row', left: '230%', bottom: '7%'}}>
<TouchableOpacity
onPress={()=>playSound(item, index)}
style={{padding: 10, top: 30, left: 30}}
>
<Ionicons name="play" color={isPlayed ? 'red' : '#555555'} size={22} />
</TouchableOpacity>
<TouchableOpacity
onPress={()=>stopSound(index)}
style={{padding: 10, top: 30, left: 20}}
>
<Ionicons name="stop" color="#555555" size={22} />
</TouchableOpacity>
</View>
</ScrollView>
);
const renderFooter = () => {
if (!loading) return null
return (
<View
style={{
paddingVertical: 15,
borderTopWidth: 1,
borderColor: '#CED0CE',
}}
>
<ActivityIndicator animating size='large' />
</View>
);
}
const renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '86%',
backgroundColor: '#CED0CE',
marginLeft: '5%',
}}
/>
)
}
return (
<ListContext.Consumer>
{(context) => (
<SafeAreaView style={styles.container}>
<FlatList
data={context.list}
renderItem={renderItem}
keyExtractor={(i, key) => 'item-' + key}
ItemSeparatorComponent={renderSeparator}
ListHeaderComponent={renderHeader}
ListFooterComponent={renderFooter}
/>
</SafeAreaView>
)}
</ListContext.Consumer>
);
};
Here's SongData.js code:
const songs = [
{
id: 1,
title: 'Hero',
ArtistName: 'Bethany Dilon',
genre: 'pop',
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.18169-9/16195530_10211997136709517_8578854309931959016_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=09cbfe&_nc_eui2=AeEvt5zlNj1bM87SMIgRXz8VjFbfh8f8mfyMVt-Hx_yZ_ISR6pzt6j1tOqssNCwDfnM&_nc_ohc=oQeQeYLPRz8AX_n81Yh&_nc_ht=scontent-los2-1.xx&oh=d87b3097c543a39067095bacfbeb004d&oe=609BF1DC',
url: require('../../assets/songs/Hero.mp3'),
},
{
id: 2,
title: 'Advertising URL',
ArtistName: 'Bethany Dilon',
genre: 'Soft Rock',
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
url:
'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/advertising.mp3',
},
{
id: 3,
title: 'Stronger',
ArtistName: 'Bethany Dilon',
genre: 'Country',
isRequire: true,
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
url: require('../../assets/songs/Stronger.mp3'),
},
{
id: 4,
title: 'Faded',
ArtistName: 'Luchee',
genre: 'Techno',
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
url: 'https://github.com/ShivamJoker/sample-songs/raw/master/Faded.mp3',
},
{
id: 5,
title: 'Solo',
ArtistName: 'Solo Cosmos',
genre: 'Afrobeat',
isRequire: true,
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
url: 'https://github.com/ShivamJoker/sample-songs/raw/master/Solo.mp3',
},
{
id: 6,
title: 'Death Bed',
ArtistName: 'Omowunmi feat Wizkid',
genre: 'Afrocentric',
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
url: 'https://github.com/ShivamJoker/sample-songs/raw/master/death%20bed.mp3',
},
{
id: 7,
title: 'Hero',
ArtistName: 'Bethany Dilon',
genre: 'pop',
isRequire: true,
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.18169-9/16195530_10211997136709517_8578854309931959016_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=09cbfe&_nc_eui2=AeEvt5zlNj1bM87SMIgRXz8VjFbfh8f8mfyMVt-Hx_yZ_ISR6pzt6j1tOqssNCwDfnM&_nc_ohc=oQeQeYLPRz8AX_n81Yh&_nc_ht=scontent-los2-1.xx&oh=d87b3097c543a39067095bacfbeb004d&oe=609BF1DC',
url: require('../../assets/songs/Hero.mp3'),
},
{
id: 8,
title: 'Advertising URL',
ArtistName: 'Bethany Dilon',
genre: 'Soft Rock',
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
url:
'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/advertising.mp3',
},
{
id: 9,
title: 'Stronger',
ArtistName: 'Bethany Dilon',
genre: 'Country',
isRequire: true,
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
url: require('../../assets/songs/Stronger.mp3'),
},
{
id: 10,
title: 'Faded',
ArtistName: 'Luchee',
genre: 'Techno',
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
url: 'https://github.com/ShivamJoker/sample-songs/raw/master/Faded.mp3',
},
{
id: 11,
title: 'Solo',
ArtistName: 'Solo Cosmos',
genre: 'Afrobeat',
isRequire: true,
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
url: 'https://github.com/ShivamJoker/sample-songs/raw/master/Solo.mp3',
},
{
id: 12,
title: 'Death Bed',
ArtistName: 'Omowunmi feat Wizkid',
genre: 'Afrocentric',
picture: 'https://scontent-los2-1.xx.fbcdn.net/v/t1.6435-0/s640x640/169534769_1185223728571457_6192837830233317030_n.jpg?_nc_cat=101&ccb=1-3&_nc_sid=9267fe&_nc_eui2=AeH2splO8pf4k-atqrUeWWApKjkWnAsELXsqORacCwQte9doNY5rNtBrWht-o_CYYR4&_nc_ohc=plbZA_Pv91EAX_quQhG&_nc_ht=scontent-los2-1.xx&tp=7&oh=abec7b3bd8ddc13b6c3c0c510a33d8dc&oe=60997696',
url: 'https://github.com/ShivamJoker/sample-songs/raw/master/death%20bed.mp3',
},
];
export default songs;
I made this code (live in Expo.io) to display JSON data categories as title and the subs as a list, it uses .map() to retrieve data from array.
import React, { useState } from 'react';
import { Text, View, StyleSheet, Button, FlatList } from 'react-native';
export default class J extends React.Component {
constructor() {
super();
this.state = {
id: '1',
name: 'Breakfast',
category: [
{
id: '1',
name: 'Burger',
items: [
{ id: '1', name: 'Vegi' },
{ id: '2', name: 'Turkey' },
],
},
{
id: '1',
name: 'Egg',
items: [
{ id: '1', name: 'Omelete' },
{ id: '2', name: 'Scrambled' },
],
},
],
};
}
render() {
return (
<View>
{this.state.category.map((item) => (
<Text>
{item.name}
{item.items.map((sub) => (
<Text> {sub.name} </Text>
))}
</Text>
))}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
width: '100%',
borderWidth: 1,
},
});
it works fine, but it shows the subs beside the main categories and I want to it to be shown like this:
Burger
Vegi
Turkey
Egg
Omelete
Scrambled
You should separate each <Text/> inside a <View/> like this:
render() {
return (
<View style={styles.container}>
{this.state.category.map((item) => (
<View>
<Text>{item.name}</Text>
{item.items.map((sub) => (
<Text style={styles.subItem}>{sub.name}</Text>
))}
</View>
))}
</View>
);
}
You can add a margin for the subItem in styles:
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
width: '100%',
borderWidth: 1,
},
subItem: {
marginLeft: 5,
},
});
Try this way
<View>
{this.state.category.map((item) => (
<Text>
{item.name}
</Text>
{item.items.map((sub) => (
<Text style={{marginLeft:30}}>{sub.name}</Text>
))}
))}
</View>
I am using a flatlist to expose all the list of ingredients I have saved on my database, but once I update the state, it is not reflecting on the flatlist component.
The flatlist component
<FlatList
horizontal
bounces={false}
key={ingredientList.id}
data={ingredientList}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => selectedIngredient(item)}>
<Card key={item.id}>
<Text key={item.title} style={styles.titleText}>{item.name}</Text>
<Text key={item.title} style={styles.titleText}>{item.isSelected?'selected':'not selected'}
</Text>
<ImageBackground key={item.illustration} source={item.illustration} style={styles.cardImage}>
</ImageBackground>
</Card>
</TouchableOpacity>
)}
keyExtractor={(item) => item.index}
/>
This is the function that find the selected item "selectedIngredient"
function selectedIngredient(item) {
console.log('received: ', item.name)
item.isSelected = !item.isSelected;
return { ...item.isSelected }
}
That component call is working when I try debbug with console.log after the "item.isSelected = !item.isSelected", but the IU is not updated. Can someone help me to understand how to fix it?
You need to set state by using either setState in a class-based component or either using useState hook in the functional component.
function selectedIngredient(item) {
console.log('received: ', item.name)
item.isSelected = !item.isSelected; //this is not how you set state
return { ...item.isSelected }
}
Screenshot:
here is our old example which I modified for your current scenario:
import React, { useState } from 'react';
import {
Text,
View,
StyleSheet,
FlatList,
TouchableOpacity,
} from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
// or any pure javascript modules available in npm
const ingredientList = [
{
id: 1,
name: 'item1',
selected: false,
},
{
id: 2,
name: 'item 2',
selected: false,
},
{
id: 3,
name: 'item 3',
selected: false,
},
{
id: 8,
name: 'item 4',
selected: false,
},
{
id: 4,
name: 'item 5',
selected: false,
},
{
id: 5,
name: 'item 6',
selected: false,
},
];
export default function App() {
const [selectedItem, setSelectedItem] = useState(null);
const [allItems, setAllItems] = useState(ingredientList);
const selectedIngredient = (item) => {
console.log('selecionado: ' + item.name);
setSelectedItem(item);
/* Below operation can be improved by passing index to the function itself.
so filtering would not be required
*/
let temp = allItems.filter((parentItem) => parentItem.id !== item.id);
item.selected = !item.selected;
temp = temp.concat(item);
temp.sort((a, b) => parseInt(a.id) - parseInt(b.id));
setAllItems(temp);
console.log(allItems);
};
return (
<View style={styles.container}>
<FlatList
style={styles.flatlist}
horizontal
bounces={false}
data={allItems}
renderItem={({ item }) => (
<TouchableOpacity
style={styles.flatListItem}
key={item.id}
onPress={() => selectedIngredient(item)}>
<Text>{item.name}</Text>
{!item.selected ? (
<Text style={{ color: 'red' }}>{'Not Selected'}</Text>
) : (
<Text style={{ color: 'green' }}>{'Selected'}</Text>
)}
</TouchableOpacity>
)}
keyExtractor={(item) => item.index}
/>
{selectedItem ? (
<View style={styles.selectedTextView}>
<Text style={styles.selectedText}>{`${selectedItem.name} ${
selectedItem.selected ? 'selected' : 'not selected'
}`}</Text>
</View>
) : (
<View style={styles.selectedTextView}>
<Text style={styles.selectedText}>{`Nothing selected`}</Text>
</View>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
flatListItem: {
width: 100,
height: 100,
backgroundColor: 'white',
margin: 5,
borderRadius: 10,
justifyContent: 'center',
alignItems: 'center',
},
selectedTextView: {
flex: 8,
backgroundColor: 'white',
margin: 5,
borderRadius: 10,
justifyContent: 'center',
alignItems: 'center',
fontSize: 20,
},
selectedText: {
fontSize: 30,
},
});
Live Demo
I have a custom card element created with View and I want mapping card element double card on one row, for example is array have 4 element 2 card items in first row other 2 card items other row so double group view per row according to the element in the array my code below is all element row
const cardView = () => {
cardItem = [
{title: 'Title1', value: 'val1'},
{title: 'Title2', value: 'val2'},
{title: 'Title3', value: 'val3'},
{title: 'Title4', value: 'val4'},
];
return (
<View style={{marginHorizontal:5}}>
<View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
{cardItem.map((item, i) => {
return (
<View style={styles.cardInner}>
<Text text={item.title} />
<Text text={item.value} />
</View>
);
})}
</View>
</View>
);
};
To achieve the desired result, You need to define flex-wrap style on the parent container and set it to 'wrap' and then provide half-width to each child element. Here is a snippet
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default function App() {
const cardItem = [
{ title: 'Title1', value: 'val1' },
{ title: 'Title2', value: 'val2' },
{ title: 'Title3', value: 'val3' },
{ title: 'Title4', value: 'val4' },
];
return (
<View style={styles.container}>
{cardItem.map((item, i) => {
return (
<View style={styles.cardInner}>
<Text>{item.title}</Text>
<Text>{item.value}</Text>
</View>
);
})}
</View>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
width: '100%',
flexWrap: 'wrap',
padding: 8,
},
cardInner: {
width: '50%'
},
});
Snack: https://snack.expo.io/#saachitech/dcffc0
more info about flex box and flex wrap property https://reactnative.dev/docs/flexbox#flex-wrap
Like use react-native-grid-component for similar problem. Can set custom number of elements per one row numColumns.
Example:
import React, { Component } from 'react';
import { StyleSheet, View } from 'react-native';
import Grid from 'react-native-grid-component';
class Simple extends Component {
_renderItem = (data, i) => (
<View style={styles.cardInner}>
<Text text={item.title} />
<Text text={item.value} />
</View>
);
render() {
return (
<Grid
renderItem={this._renderItem}
data={[
{title: 'Title1', value: 'val1'},
{title: 'Title2', value: 'val2'},
{title: 'Title3', value: 'val3'},
{title: 'Title4', value: 'val4'},
]}
numColumns={2}
/>
);
}
}
const styles = StyleSheet.create({
...
});
You can do it like this:
const cardView = () => {
cardItem = [
{ title: 'Title1', value: 'val1' },
{ title: 'Title2', value: 'val2' },
{ title: 'Title3', value: 'val3' },
{ title: 'Title4', value: 'val4' },
];
mappedCards = cardItem.map((item) => {
return (
<Text text={item.title} />
)
})
return (
<View style={{ marginHorizontal: 5 }}>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<View style={styles.cardInner}>
{mappedCards}
</View>
</View>
</View>
);
};
I am new to React Native. I am making a music app and I'm using the react-native-track-player module which works. But now, I'm trying to pass songlist as props from my Flatlist to the player component.
So first, I am able to show the moods. Then when I pass props/move to Songlist screen I am be able to show the songlist and it will display the title and artist in a Flatlist. So when I click on one of them, It will go to the Play screen. I want to be able to pass the props and play the song. But the song will not be played and crash. I am not sure whether I am passing the props properly. I will really appreciate if anyone can help me with this issue.
This is my Cluster1 screen (first screen)
export default class Cluster1 extends Component{
render(){
return(
<View style={styles.container}>
<SectionList
renderItem={({item,index})=>{
return(
<SectionListItem item={item} index={index}> </SectionListItem>);}}
renderSectionHeader={({ section }) => {
return (<SectionHeader section={section} />);}}
sections={ClusterData}
keyExtractor={(item, index) => item.name}>
</SectionList>
</View>
);
}}
class SectionHeader extends Component {
render() {
return (
<View style={styles.header}>
<Text style={styles.headertext}>
{this.props.section.title}
</Text>
<TouchableOpacity onPress={ () => Actions.SongList({ section: this.props.section}) }>
<Text style ={styles.Play}> Play
</Text>
</TouchableOpacity>
</View>
);
}}
class SectionListItem extends Component{
render(){
return(
<View>
<Text style={styles.moodname}>{this.props.item.name}</Text>
</View>
);
}
}
This is my SongList screen (second screen)
export default class App extends Component {
render() {
return (
<View>
<FlatList
data={this.props.section.songlist}
renderItem={({item,index,rowId})=>{
return(
<FlatListItem item={item} index={index}>
</FlatListItem>);}}>
</FlatList>
</View>
);}}
class FlatListItem extends Component{
render(){
return(
<View>
<TouchableOpacity onPress={ () => Actions.Play({songIndex: 0, songlist: this.props.item.songlist, item: this.props.item}) }>
<Text style={styles.itemTitle}>{this.props.item.songtitle}</Text>
<Text style={styles.itemArtist}>{this.props.item.artist}</Text>
</TouchableOpacity>
</View>
);}}
So when I click on the songtitle/artist, the app will stop. I think the error could be await TrackPlayer.add(this.props.item.songlist); but I am not sure.
This is my Play screen
import TrackPlayer from 'react-native-track-player';
export default class Play extends Component{
componentDidMount()
{
TrackPlayer.setupPlayer().then(async () => {
// Adds a track to the queue
await TrackPlayer.add(this.props.item.songlist);
// Starts playing it
TrackPlayer.play();
});
}
onPressPlay = () => {
TrackPlayer.play();
};
onPressPause = () => {
TrackPlayer.pause();
};
render() {
return (
<View style={styles.container}>
<View style= {{flexDirection :'column'}}>
<TouchableOpacity style= {styles.play} onPress = {this.onPressPlay}>
<Text style = {{fontWeight:'bold',textAlign:'center',color:'white'}}>Play</Text>
</TouchableOpacity>
<TouchableOpacity style= {styles.pause} onPress = {this.onPressPause}>
<Text style = {{fontWeight:'bold',textAlign:'center',color:'white'}}>Pause</Text>
</TouchableOpacity>
</View>
</View>
);}}
This is my where I get my data in another file
const ClusterData = [
{ title: 'Cluster1',
data:
[
{name: 'passionate'},
{name: 'rousing'},
{name: 'confident'},
{name: 'boisterous'},
{name: 'rowdy'}
],
songlist:
[
{
id: '2222',
url: 'http://tegos.kz/new/mp3_full/Post_Malone_-_Better_Now.mp3',
title: 'Better Now',
artist: 'Post Malone',
},
{
id: '2',
url: 'http://tegos.kz/new/mp3_full/5_Seconds_Of_Summer_-_Youngblood.mp3',
title: 'YoungBlood',
artist: '5SOS',
},
]
},
{ title: 'Cluster2',
data:
[
{name: 'rollicking'},
{name: 'cheerful'},
{name: 'fun'},
{name: 'sweet'},
{name: 'amiable'},
{name: 'natured'}
],
songlist:
[
{
id: '1111',
url: 'http://tegos.kz/new/mp3_full/Yellow_Claw_and_San_Holo_-_Summertime.mp3',
title: 'Summertime',
artist: 'Yellow Claw',
},
{
id: '1',
url: 'http://tegos.kz/new/mp3_full/Luis_Fonsi_feat._Daddy_Yankee_-_Despacito.mp3',
title: 'Despacito',
artist: 'Luis Fonsi',
},
]
},
You are passing wrong props in FlatListItem, now there is no songlist object beacause item itself is a songlist item,
So just pass it like this Actions.Play({songIndex: 0, item: this.props.item}) }> and Update inside Play class by replacing this.props.item.songlist to this.props.item
Below is the complete working example
import React, { Component } from 'react';
import {
View,
Text,
FlatList,
TouchableOpacity,
SectionList,
} from 'react-native';
import TrackPlayer from 'react-native-track-player';
const ClusterData = [
{
title: 'Cluster1',
data: [
{ name: 'passionate' },
{ name: 'rousing' },
{ name: 'confident' },
{ name: 'boisterous' },
{ name: 'rowdy' },
],
songlist: [
{
id: '2222',
url: 'http://tegos.kz/new/mp3_full/Post_Malone_-_Better_Now.mp3',
title: 'Better Now',
artist: 'Post Malone',
},
{
id: '2',
url:
'http://tegos.kz/new/mp3_full/5_Seconds_Of_Summer_-_Youngblood.mp3',
title: 'YoungBlood',
artist: '5SOS',
},
],
},
{
title: 'Cluster2',
data: [
{ name: 'rollicking' },
{ name: 'cheerful' },
{ name: 'fun' },
{ name: 'sweet' },
{ name: 'amiable' },
{ name: 'natured' },
],
songlist: [
{
id: '1111',
url:
'http://tegos.kz/new/mp3_full/Yellow_Claw_and_San_Holo_-_Summertime.mp3',
title: 'Summertime',
artist: 'Yellow Claw',
},
{
id: '1',
url:
'http://tegos.kz/new/mp3_full/Luis_Fonsi_feat._Daddy_Yankee_-_Despacito.mp3',
title: 'Despacito',
artist: 'Luis Fonsi',
},
],
},
];
export class MusicPlayer extends Component {
state = {
showSongList: false,
activeSection: null,
};
updateState = item => {
this.setState(item);
};
render() {
return (
<View style={{ flex: 1, paddingTop: 20 }}>
{this.state.showSongList ? (
<SongList section={this.state.activeSection} />
) : (
<SectionList
renderItem={({ item, index }) => {
return <SectionListItem item={item} index={index} />;
}}
renderSectionHeader={({ section }) => {
return (
<SectionHeader
section={section}
updateState={this.updateState}
/>
);
}}
sections={ClusterData}
keyExtractor={(item, index) => item.name}
/>
)}
</View>
);
}
}
class SectionHeader extends Component {
render() {
return (
<View style={{ margin: 20, marginBottom: 10 }}>
<Text style={{ fontWeight: 'bold' }}>{this.props.section.title}</Text>
<TouchableOpacity
onPress={() =>
this.props.updateState({
showSongList: true,
activeSection: this.props.section,
})
}
>
<Text style={{ color: 'blue' }}> Play</Text>
</TouchableOpacity>
</View>
);
}
}
class SectionListItem extends Component {
render() {
return (
<View>
<Text style={{ margin: 5, marginLeft: 20, fontStyle: 'italic' }}>
{this.props.item.name}
</Text>
</View>
);
}
}
export class SongList extends Component {
state = {
isPlayActive: false,
};
startPlay = data => {
this.setState({
isPlayActive: true,
data: data,
});
};
render() {
return (
<View style={{ flex: 1 }}>
<FlatList
data={this.props.section.songlist}
renderItem={({ item, index, rowId }) => {
return (
<FlatListItem
item={item}
index={index}
startPlay={this.startPlay}
/>
);
}}
/>
{this.state.isPlayActive && <Play {...this.state.data} />}
</View>
);
}
}
class FlatListItem extends Component {
render() {
return (
<View style={{ backgroundColor: '#555', height: 80, marginTop: 20 }}>
<TouchableOpacity
onPress={() =>
this.props.startPlay({
songIndex: 0,
item: this.props.item,
})
}
>
<Text
style={{
paddingTop: 10,
textAlign: 'center',
fontSize: 20,
color: '#FFF',
}}
>
{this.props.item.title}
</Text>
<Text
style={{
textAlign: 'center',
fontSize: 15,
paddingTop: 10,
color: '#FFF',
}}
>
{this.props.item.artist}
</Text>
</TouchableOpacity>
</View>
);
}
}
export class Play extends Component {
componentDidMount() {
TrackPlayer.setupPlayer().then(async () => {
// Adds a track to the queue
await TrackPlayer.add(this.props.item);
// Starts playing it
TrackPlayer.play();
});
}
onPressPlay = () => {
TrackPlayer.play();
};
onPressPause = () => {
TrackPlayer.pause();
};
render() {
return (
<View style={{ height: 400 }}>
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
style={{
backgroundColor: '#f0f0f0',
height: 40,
flex: 1,
alignItems: 'center',
justifyContent: 'center',
marginRight: 10,
}}
onPress={this.onPressPlay}
>
<Text
style={{
fontWeight: 'bold',
textAlign: 'center',
color: 'black',
}}
>
Play
</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
flex: 1,
backgroundColor: '#f0f0f0',
height: 40,
alignItems: 'center',
justifyContent: 'center',
}}
onPress={this.onPressPause}
>
<Text
style={{
fontWeight: 'bold',
textAlign: 'center',
color: 'black',
}}
>
Pause
</Text>
</TouchableOpacity>
</View>
</View>
);
}
}