I have a rendered list and I would like it when a change in status is generated the entire FlatList is recharged
what I have is a search engine and I want that when it brings the new data the FlatList will refresh itself with the new information
I need that every time you enter a letter in the search engine the FlatList will recharge
async buscar(buscar) {
this.setState({refreshing: true});
const coins = await ajax.searchProd(buscar);
this.setState({coins});
console.log(coins);
this.setState({refreshing: false});
}
render() {
return (
<View style={styles.container}>
<Image style={styles.logoHeader} source={require('../../public/images/productos.png')}/>
<View style={styles.containerSearch}>
<TextInput
style={styles.inputBuscar}
placeholder={'Buscar Productos'}
underlineColorAndroid={"transparent"}
onChangeText={(buscar) => {
this.setState({buscar: buscar});
this.buscar(this.state.buscar);
console.log(this.state.buscar);
}}
/>
<Image style={styles.imageSearch} source={require('../../public/images/search.png')}/>
</View>
<View style={styles.containerPro}>
<FlatList
extraData={this.state.coins}
data={this.state.coins}
keyExtractor={(item) => item.id.toString()}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh}
/>
}
renderItem={({item}) => {
let url = 'http://laeconomiadelsur.com/upload/' + item.foto;
const tableData = [
[<View>
<Image source={{uri: url}} style={{
width: 50,
height: 70,
}}/>
</View>,
],
[<View style={styles.cellIcons}>
<Text
style={styles.textCells}>{item.nombre}</Text>
<Text
style={styles.textCellsDescription}>{item.descripcion}</Text>
<Text
style={styles.textCellsPrecio}>{numeral(item.precio).format('$0,0')}</Text>
</View>,
],
[<View>
<Text style={styles.cantidad1}>seleccionar: </Text>
<View>
<NumericInput
onChange={(value) => {
let total = value * item.precio;
console.log(value);
console.log(total)
}}
totalWidth={calcSize(250)}
totalHeight={calcSize(70)}
minValue={0}
iconSize={15}
step={1}
sepratorWidth={0}
borderColor={'transparent'}
inputStyle={{
backgroundColor: 'rgb(252,226,227)',
borderTopColor: 'rgb(226,0,30)',
borderBottomColor: 'rgb(226,0,30)',
borderWidth: 1,
fontFamily: "NeutraText-BookSC",
fontSize: 17
}}
containerStyle={{
borderWidth: 1,
borderColor: 'rgb(226,0,30)',
backgroundColor: 'transparent',
}}
rounded
textColor='#000000'
rightButtonBackgroundColor={'rgb(235,209,210)'}
leftButtonBackgroundColor={'rgb(235,209,210)'}
/>
</View>
<Text style={styles.cantidad}>cantidad</Text>
</View>,]
];
return (
<View style={{flex: 1}} key={item.id}>
<Table style={styles.table} borderStyle={{borderWidth: 2, borderColor: 'white'}}
key={item.id}>
<Cols data={tableData} flexArr={[1, 2, 2]} style={styles.cells}
key={item.id}/>
</Table>
</View>
);
}}
/>
</View>
</View>
);
<TextInput
style={styles.inputBuscar}
placeholder={'Buscar Productos'}
underlineColorAndroid={"transparent"}
onChangeText={(buscar) => {
/* Updated buscar value won't be available in next line instantly
* just after the setState. So, better set buscar State in
* this.buscar() Function.
*/
/* this.setState({buscar: buscar}); Move to buscar Function*/
this.buscar(buscar).then(()=>{
console.log(this.state.buscar);
}).catch((e)=> console.log("Error: ",e))
}}
/>
An Async function always returns a promise object. So, while calling buscar function you should handle the promise.
async buscar(buscar) {
this.setState({
refreshing: true,
buscar: buscar,
});
const coins = await ajax.searchProd(buscar);
console.log(coins);
this.setState({
coins: conins,
refreshing: false
});
}
In Flatlist ExtraData property should contain the this.state
extraData={this.state}
Related
I am having this issue form a long time. There are some solution available online but nothing really helped. Can anybody provide me a solution or if there any online video available on how to install react native track player with expo, please share the link here. This would be great help. Thank you.
This is the error I am facing:
error image
And here is my code:
const song = {
artwork: "https://d3t3ozftmdmh3i.cloudfront.net/production/podcast_uploaded_episode/24617089/24617089-1650969292082-de5918979b327.jpg",
date: "Tue, 26 Apr 2022 06:57:07 GMT",
duration: "69",
title: "I am a Little Teapot Nursery - Rhyme Song",
url: "https://anchor.fm/s/935348e4/podcast/play/51109264/https%3A%2F%2Fd3ctxlq1ktw2nl.cloudfront.net%2Fproduction%2F2022-3-25%2F261575908-44100-2-2637c955d6697.mp3",
}
const setupPlayer = async () => {
await TrackPlayer.setupPlayer()
await TrackPlayer.add(song)
await TrackPlayer.play()
}
const RssNode = ({data, songs}) => {
const playbackState = usePlaybackState()
useEffect(()=>{
setupPlayer(songs)
},[])
const toggolePlayback = async(playbackState) => {
const currentTrack = await TrackPlayer.getCurrentTrack();
if (currentTrack !== null){
if (playbackState == State.Paused){
await TrackPlayer.play()
} else {
await TrackPlayer.pause()
}
}
}
console.log(songs.map((i)=>i.title))
return (
<View style={{flex:1, width: (width), alignItems: "center", top:35}}>
<Animated.FlatList
data = {data}
renderItem= {({item})=>{
return <RenderSong
Image={item.itunes.image}
title= {item.title}
/>
}}
horizontal
paginEnabled
scrollEnabled={true}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
snapToInterval={width}
disableIntervalMomentum
/>
<View style = {{width:width, height:height*0.4, alignItems:"center", top:25}}>
<Text style={{color:"#ffffff", }}>{data[0].title}</Text>
<View style={{width:width, height:height*0.1, justifyContent:"center", alignItems:"center"}}>
<Slider value={0} minimumValue={0} maximumValue={1} thumbTintcolor= "#FFF" minimunTrackTintColor="#FFF" maximumTrackTintColor="#FFF"
style={{width: (width * 0.8), height: 40, marginVertical:10}}
/>
</View>
<View style={{width:width * 0.7, flexDirection:"row", height:height*0.05, top:-(height*0.03), justifyContent:"space-between"}}>
<Text style={{color:"#ffffff", }}>{0}</Text>
<Text style={{color:"#ffffff", }}>{0}</Text>
</View>
<View style={{flexDirection:"row", height: (width * 0.94)/4, width:width*0.8, borderRadius:10, top:-50, justifyContent:"space-between", alignItems:"center", marginHorizontal:30 }}>
<IconMaterialIcons name={"shuffle-on"} size={30} color="#FFF" onPress={()=>{changeShuffle()}} />
<Icon name="step-backward" size={30} color="#FFF" onPress={()=>alert("Hello")} />
<Icon name={playbackState === State.Playing ? "pause-circle" : "play-circle"} size={60} color="#FFF" onPress={()=>toggolePlayback(playbackState)} />
<Icon name="step-forward" size={30} color="#FFF" onPress={()=>alert("Hello")} />
<IconMaterialIcons name={"repeat-on"} size={30} color="#FFF" onPress={()=>changeRepeat()} />
</View>
</View>
</View>
);
}
export default RssNode
error
Please help me to solve this problem. Thank you so much.
I want to change the state when I get id of 5/6 or 7, after TouchableOpacity. Because I want to show the "Other Things" button one time whether id is 5/6 or 7.
export function HomePage({ navigation }) {
const [parentServiceCheck, setParentServiceCheck] = useState({ check: '0' });
return (
<View>
<FlatList numColumns={2} contentContainerStyle={{ margin: 7, flex: 1 }} keyExtractor={(item, index) => item.id} data={allService} renderItem={itemData => (
<View style={{ flexDirection: 'column', flex: 1 }}>
{
(itemData.item.id == 5 || itemData.item.id == 6 || itemData.item.id == 7) && parentServiceCheck.check == '0' ?
<TouchableOpacity onPress={() => pressHandler(itemData.item.id)} style={{ margin: 7 }}>
<Card titlebtn="Other Things" src={itemData.item.service_image} sty={{ height: 180, }} />
</TouchableOpacity>
// Now here I want to setParentServiceChildCheck({check: '1'}) when itemData.item.id has 5/6/7
:
<TouchableOpacity onPress={() => pressHandler(itemData.item.id)} style={{ margin: 7 }}>
<Card titlebtn={itemData.item.service_name} src={itemData.item.service_image} sty={{ height: 180, }} />
</TouchableOpacity>
}
</View>
)}
/>
</View>
)
}
You can't really update or execute any JS code like that. I would suggest to go through few training to learn about how things work in React JSX.
For now, if you want to update the state then you should be good to use it in useEffect as shown below
export default function HomePage({ navigation }) {
const [parentServiceCheck, setParentServiceCheck] = useState({ check: '0' });
useEffect(() => {
const hasValidId = allService.find(_hasValidId);
// This will get called only once after first render
// This will execute only when id's are 5, 6 or 7 which is your requirement
if (hasValidId) {
setParentServiceChildCheck({ check: '1' });
}
}, []);
const _hasValidId = itemData => {
const itemId = itemData?.item?.id;
const validItemIds = [5, 6, 7];
return validItemIds.includes(itemId);
};
const _renderItem = itemData => {
const itemId = itemData?.item?.id;
let content = null;
if (_hasValidId(itemData)) {
if (parentServiceCheck.check === '0') {
content = (
<TouchableOpacity onPress={() => pressHandler(itemId)} style={{ margin: 7 }}>
<Card titlebtn="Other Things" src={itemData.item.service_image} sty={{ height: 180 }} />
</TouchableOpacity>
);
} else {
content = (
<TouchableOpacity onPress={() => pressHandler(itemId)} style={{ margin: 7 }}>
<Card
titlebtn={itemData.item.service_name}
src={itemData.item.service_image}
sty={{ height: 180 }}
/>
</TouchableOpacity>
);
}
}
return <View style={{ flexDirection: 'column', flex: 1 }}>{content}</View>;
};
return (
<View>
<FlatList
numColumns={2}
contentContainerStyle={{ margin: 7, flex: 1 }}
keyExtractor={(item, index) => item.id}
data={allService}
renderItem={_renderItem}
/>
</View>
);
}
FYI, you might need to change few lines as the whole component code is not shared and I don't know about your business logic.
You should never update state in return / render function. It will make infinite rendering loop.
In my case I am writing a Facebook clone like application, but much simpler. I put each item in FlatList and render them.
To "like" a post, I press the "like" button on the post and the "like" button turns yellow and the likes count increase by 1 ( Also I call addLike API Function after clicking ), I press it again, it turns gray and likes count decrease by one ( Also I Call removeLike API Funtion ).
This is what I have so far: I store all the loaded posts with redux - this.props, each post has a property called "liked", which is boolean, indicating whether this user has liked this post or not, when user presses "like", Now I doing when user like the post I call the addLike() action and fetch all the posts to feed again. I want to do this without fetching data again and again
FlatList Component
<FlatList
style={styles.postList}
data={this.props.postData}
extraData={this.props}
maxToRenderPerBatch={10}
keyExtractor={item => {
return item.id;
}}
ItemSeparatorComponent={() => {
return <View style={styles.separator} />;
}}
renderItem={post => {
const item = post.item;
this.state.userisLiked = item.likedUsers.find(
user => user.id == this.state.userDetails.id,
);
// console.log('Returning Is Liked ', isLiked);
return (
<View style={styles.card}>
<View>
{item.postImage ? (
<TouchableOpacity
onPress={() =>
this.showSelectedImageFullView(item.postImage)
}>
<ImageBackground
style={styles.cardImage}
source={{
uri: Strings.AWSS3_POST_IMAGE + item.postImage,
}}>
<View style={styles.overlay} />
</ImageBackground>
</TouchableOpacity>
) : (
<View></View>
)}
</View>
<View style={{flexDirection: 'row'}}>
<Image
source={
item.user.profilePicture
? {
uri:
Strings.AWSS3_USER_PROFILE_AVATAR +
item.user.profilePicture,
}
: Images.IMAGE_PLACEHOLDER
}
style={styles.postUserImage}
/>
<View style={{flexDirection: 'column'}}>
<Text style={styles.postUserName}>
{item.user.firstName} {item.user.lastName}
</Text>
<TimeAgo
style={styles.postedTime}
time={item.createdAt}
interval={20000}
/>
</View>
<TouchableOpacity
style={styles.postMoreInfoIcon}
onPress={() => this.toggleModal(item)}>
<Image
source={Images.POST_MORE_INFO}
style={styles.postMoreInfoIcon}
/>
</TouchableOpacity>
</View>
<TouchableOpacity onPress={() => this.homeMoreInfoScreen(item)}>
<View style={{flexDirection: 'column'}}>
<Text style={styles.postTitle}>{item.title}</Text>
<Text style={styles.postBody} numberOfLines={2}>
{item.description}
</Text>
</View>
</TouchableOpacity>
<View style={styles.cardFooter}>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity
onPress={() => {
this.handleUserLikes(item);
}}>
{this.state.userisLiked ? (
<Image
source={Images.POST_LIKE_CHECKED}
style={{
width: 20,
height: 20,
resizeMode: 'contain',
}}
/>
) : (
<Image
source={Images.POST_LIKE_UNCHECKED}
style={{
width: 20,
height: 20,
resizeMode: 'contain',
}}
/>
)}
</TouchableOpacity>
<Text
selectable={true}
onPress={() => this.toggleLikeModal(item)}
style={{
fontFamily: AppStyles.primaryFont,
fontSize: 15,
color: AppStyles.colorWhite,
marginLeft: 5,
}}>
{item.likesCount} Likes
</Text>
</View>
<View style={{flexDirection: 'row', marginLeft: 20}}>
<TouchableOpacity
onPress={() => this.homeMoreInfoScreen(item)}>
<Image
source={Images.POST_COMMENT}
style={{width: 20, height: 20, resizeMode: 'contain'}}
/>
</TouchableOpacity>
<Text
selectable={true}
onPress={() => this.homeMoreInfoScreen(item)}
style={{
fontFamily: AppStyles.primaryFont,
fontSize: 15,
color: AppStyles.colorWhite,
marginLeft: 5,
}}>
{item.commentsCount} Comments
</Text>
</View>
<View
style={{
flexDirection: 'row',
marginLeft: 10,
position: 'absolute',
right: 100,
top: 20,
}}>
</View>
<View
style={{
flexDirection: 'row',
marginLeft: 10,
position: 'absolute',
right: 10,
top: 20,
}}>
<TouchableOpacity
onPress={() => this.homeMoreInfoScreen(item)}>
<Text
style={{
fontFamily: AppStyles.primaryFont,
fontSize: 15,
color: AppStyles.colorWhite,
}}>
Comment
</Text>
</TouchableOpacity>
</View>
</View>
</View>
);
}}
/>
Handle User Like Action
//Add Likes to selected post click listner
handleUserLikes = item => {
//Check user already liked the post
const isLiked = item.likedUsers.find(
user => user.id == this.state.userDetails.id,
);
if (isLiked) {
this.props.removeLikeFromPost(item.id, this.state.user_token);
this.props.fetchPostData(this.state.user_token);
} else {
this.props.addLikeToPost(
item.id,
this.state.user_token,
this.state.userDetails.id,
);
this.props.fetchPostData(this.state.user_token);
}
};
Assuming that the items are available as props. You can handle the data alteration in the reducer instead of your React component. first what you have to do is
handleUserLikes = item => {
this.props.addLikeToPost({
item_id:item.id,
user_token:this.state.user_token,
user_id:this.state.userDetails.id,
});
};
inside your redux code fire a function that handles the logic.
const userLike =(state,payload)=>{
let Newitem = null;
let item= state.item.find(
user => item.id == payload.item_id
);
let itemIndex = state.item.findIndex(
user => user.id == payload.item_id
);
let isLiked = item.likedUsers.find(user=>user.id===payload.user_id);
if(isLiked){
Newitem = {...item,likedUsers:item.likedUsers.filter(user=>user.id!==payload.user_id)}
} else{
Newitem = {...item,likedUsers:[...item.likedUsers,payload.user_id]}
}
let Newitems = [
state.items.slice(0, itemIndex),
Newitem,
state.items.slice(++itemIndex)
];
return {...state,items:Newitems}
}
This method userLike should be called inside the reducer switch statement which corresponds to your particular action. like this
function appReducer(state = initialState, action) {
switch (action.type) {
.........
case 'YOU_ACTION' :
return userLike(state,action);
}
}
In this manner, you don't have to fetch the items data again and again. But make sure you send the data to the back end saying the post is liked or unliked.
const addLikeToPost = (data) => dispatch => {
// you can send a request to your back end here without Awaiting.
// data is passed from the addLikeToPost method called from you react component.
dispatch({action:'YOU_ACTION',payload:data});
}
First of all thanks to #TRomesh for his answer.
Based on that I found a solution for this issue easily
My Button Action Call
handleUserLikes = item => {
this.props.addLikeToPost({
item_id:item.id,
user_token:this.state.user_token,
user_id:this.state.userDetails.id,
});
};
Redux Reducer Function -> This is the part I edited from above answer
const userLike = (state, payload) => {
console.log('TCL: userLike -> payload', payload.payload);
console.log('TCL: userLike -> state.postData', state.postData);
let item = state.postData.find(user => user.id == payload.payload.item_id);
let local_data = state.postData;
let isLiked = item.likedUsers.find(
user => user.id === payload.payload.user_id,
);
if (isLiked) {
local_data = local_data.map(data => {
if (data.id == payload.payload.item_id) {
data.likesCount = Number(data.likesCount - 1);
}
return data;
});
} else if (isLiked == undefined || isLiked == null) {
local_data = local_data.map(data => {
if (data.id == payload.payload.item_id) {
data.likesCount = Number(data.likesCount + 1);
}
return data;
});
}
return {...state, postData: local_data};
};
Cheers !
I'm trying to pass some data from container to modal, and i've done this. it got error undefined is not an object evaluating (evaluating _this.props.status) is there anything i did worng? what should i call in props
these are my codes
container.js
buildPanel(index, item) {
let panel = [];
let keys = DBkeys['Requests'].MyRequest;
let status = item[keys['status']];
panel.push(<View style={{ position: 'absolute', right: 0, bottom: 0, padding: normalize(5), alignItems: 'center' }} key={'status'}>
<TouchableOpacity onPress={this.handleShowModal()}>
<Icon name={img.itemStatus[status].name} type={img.itemStatus[status].type} color={img.itemStatus[status].color} size={normalize(38)} />
</TouchableOpacity>
</View>);
return panel;
}
<View style={[styles.panelContainer, status === 'success' ? {} : { backgroundColor: color.white }]}>
<FlatList
showsVerticalScrollIndicator={false}
progressViewOffset={-10}
refreshing={this.state.refreshing}
onRefresh={this.onRefresh.bind(this)}
onMomentumScrollEnd={(event) => event.nativeEvent.contentOffset.y === 0 ? this.onRefresh() : null}
data={content}
renderItem={({ item }) => item}
keyExtractor={(item, key) => key.toString()}
/>
</View>
<IconModal visible={this.state.modalVisible} close={this.handleDismissModal} status='test' desc='test' />
IconModal.js
const IconModal = (props) => {
return(
<Modal
isVisible={props.visible}
onBackdropPress={props.close}
>
<View style={styles.dialogBox}>
<View style={styles.icon}>
<Icon></Icon>
</View>
<View style={styles.text}>
<Text style={styles.status}>{this.props.status}</Text>
<Text>{this.props.desc}</Text>
</View>
<TouchableOpacity onPress={props.close}>
<View>
<Text style={styles.buttonText}>GOT IT</Text>
</View>
</TouchableOpacity>
</View>
</Modal>
)
}
IconModal.propTypes ={
visible: PropTypes.bool.isRequired,
close: PropTypes.func,
}
Use double quotes while passing string to the component. like status="test" desc="test" instead of status='test' desc='test' . and instead of this.props.status use props.status. same with this.props.desc
Remove the this keyword. It should be just props.status and props.desc
I've got a SectionList, and for every row in the list I want to be able to detect a click event.
renderList() {
if (this.state.searching) {
return (
<SectionList
sections={this.state.data}
renderSectionHeader={this.props.renderSectionHeader}
renderItem={this.props.renderItem}
/>
);
}
return null;
}
render() {
return (
<View style={styles.container}>
<Animated.View
style={{ opacity: 1 - this.state.backgroundColor }}
pointerEvents={this.state.searching ? 'none' : undefined}
>
{this.props.children}
</Animated.View>
<Animated.View
style={[
styles.backgroundColorView,
{ opacity: this.state.backgroundColor },
]}
/>
<Animated.View
style={[styles.searchResults, { top: this.state.yPos }]}
>
<TextInput
ref={(input) => { this.searchBar = input; }}
style={styles.textInput}
value={this.props.query}
onChangeText={this.onChangeText}
maxLength={100}
placeholder={this.props.placeholder}
onFocus={this.onFocus}
onBlur={this.onUnSearch}
/>
{this.renderList()}
</Animated.View>
</View>
);
For my renderItem method, I'm passing in the following PureComponent, which is just a Text contained in a TouchableHighlight.
class SubjectSearchItem extends React.PureComponent {
render() {
const item = this.props.item;
return (
<TouchableHighlight
onPress={() => console.log(item)}
>
<View style={{
marginHorizontal: 20,
marginVertical: 10,
}}
>
<Text>{`${item.item.long_name} (${item.item.short_name})`}</Text>
</View>
</TouchableHighlight>
);
}
}
and here's the renderItem prop I'm passing in
const renderItem = item => (
<SubjectSearchItem
item={item}
/>
);
The problem is, no click events are being detected. The row isn't getting highlighted, and the onPress isn't being fired. Any ideas?
Note: seems like this has been an issue for a little while