I'm trying to change the background of only one item in this agenda but with my code, when I click on an item, it changes the background color of all of them and not just the one I clicked : screen before clicking on item screen after clicking
The problem amounts to knowing just how to change the style of just one item in the agenda and not the style of all of them.
Here is my code :
import React, { useState } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
} from 'react-native';
import moment from 'moment';
import { Avatar, Card } from 'react-native-paper';
import {Agenda} from "react-native-calendars";
const timeToString = (time) => {
const date = new Date(time);
return date.toISOString().split('T')[0];
};
export default function calendarScreen () {
const [color, setColor] = useState(
{backgroundColor: 'white', backgroundColor2: 'white', texte: 'Disponible', pressed: false}
);
const changeColor = () => {
if (!color.pressed) {
setColor({backgroundColor: 'lightgreen', backgroundColor2: 'white', texte: 'Réservé', pressed: true})
} else {
setColor({backgroundColor: 'white', backgroundColor2: 'green', texte: 'Disponible', pressed: false})
}
};
const [items, setItems] = useState({});
const loadItems = (day) => {
setTimeout(() => {
for (let i = -15; i < 85; i++) {
const time = day.timestamp + i * 24 * 60 * 60 * 1000;
const strTime = timeToString(time);
if (!items[strTime]) {
items[strTime] = [];
const numItems = 1;
for (let j = 0; j < numItems; j++) {
items[strTime].push({
name: 'Disponible',
height: Math.max(50, Math.floor(Math.random() * 150)),
style: color.backgroundColor
});
}
}
}
const newItems = {};
Object.keys(items).forEach(key => {newItems[key] = items[key];});
setItems(newItems);
}, 1000);
};
const renderItem = (item, firstItemInDay) => {
return (
<TouchableOpacity style={{ marginTop: 17, marginRight: 10}} onPress={(changeColor)}>
<Card style={ { backgroundColor : color.backgroundColor }}>
<Card.Content>
<View style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
}}>
<Text>{item.name}</Text>
<Avatar.Text label="J" />
</View>
</Card.Content>
</Card>
</TouchableOpacity>
)
};
return (
<View style={{flex:1}}>
<Agenda
items={items}
loadItemsForMonth={loadItems}
selected={'2020-09-23'}
renderItem={renderItem}
/>
</View>
)
}
Thanks a lot in advance for your help
The problem is that the color state is bound to every item you're rendering. Every item you're rendering should know about itself whether it is active or not, i.e. have its own state.
So you could do something like this:
Further explanation of the above approach
I put the style and possible text values outside of any component and I created a custom
CalendarItem
component that is passed to yourrenderItem
function.Because
CalendarItem
is a functional component it can have its own state. We don't have to hold an entire object in the state in this instance, since the only we really want to know is if an item is active or not. We can update theactive
state on press and then conditionally renderCalendarItem
based on your active and inactive styles and data.