I am trying to change the active style of an element in an array. As shown in the image below - when you press on the day the styles will change to add a border around it.
So far I am struggling to change the boolean state of each element individually and track when I press on another date it will change the active state to false. Here is my code so far:
function Journal() {
const day = new Date().getDay();
const month = new Date().getMonth();
const dayNumber = new Date().getDate();
const [active, setActive] = useState(false);
let [fontsLoaded] = useFonts({
Roboto_400Regular
});
if (!fontsLoaded) {
return <></>;
} else {
return (
<ScrollView>
<CheckInHeader/>
<View style={{margin: 32}}>
<Text style={{fontSize: 18, fontFamily: 'Roboto_400Regular'}}>Today</Text>
<View style={{flexDirection: 'row'}}>
<Text
style={{
fontSize: 14,
fontFamily: 'Roboto_400Regular',
color: '#878787'
}}>{getDay(day)} </Text>
<Text style={{
fontSize: 14,
fontFamily: 'Roboto_400Regular',
color: '#878787'
}}>{getDayNumber(dayNumber)} </Text>
<Text style={{
fontSize: 14,
fontFamily: 'Roboto_400Regular',
color: '#878787'
}}>{getMonth(month)}</Text>
</View>
<JournalEntry/>
<View style={{flexDirection: 'row-reverse', justifyContent: 'space-around', marginTop: 64}}>
{lastSevenDays().map((result, i) => {
return (
<TouchableOpacity
style={[lastSevenDays()[i].active ? {
alignItems: 'center',
borderColor: '#DBDBDB',
borderWidth: 1,
borderRadius: 16,
minWidth: 48,
padding: 8
} : {alignItems: 'center'}]}
onPress={() => {
lastSevenDays()[i].active
}}
>
<Text>{result.day?.slice(0, 3)}</Text>
<Text>{result.dayNumber}</Text>
</TouchableOpacity>
)
})}
</View>
</View>
</ScrollView>
);
}
}
export const lastSevenDays = (): {day: string | undefined, dayNumber: number, month: string | undefined, active: boolean}[] => {
let result = [];
for (let i=0; i<7; i ) {
let d = new Date();
d.setDate(d.getDate() - i);
result.push({day: getDay(d.getDay()), dayNumber: d.getDate(), month: getMonth(d.getMonth()), active: false})
}
return (result);
}
Any help on how to do this would be brilliant! Thanks :)
CodePudding user response:
I see two major issues:
- First is more related to best practices and code readability: I don't think you need to use lastSevenDays().map inside html (and even multiple times). It would be best to store the value in an array (something like renaming the actual lastSevenDays function to getLastSevenDays and then use a variable const lastSevenDays = getLastSevenDays() and just use that variable.
- It would be best if you would use a state just for the active day rather than changing the active state of the element individually. Easiest way would be just to store the active day index in a state.
So somthing like:
const [activeDay, setActiveDay] = useState(); //feel free to default the active day here
...
...
<TouchableOpacity
style={[activeDay === i ? {
alignItems: 'center',
borderColor: '#DBDBDB',
borderWidth: 1,
borderRadius: 16,
minWidth: 48,
padding: 8
}
:
{alignItems: 'center'}
]}
onPress={() => {
setActiveDay(i)
}}>
If there is any reason to avoid using index you can replace it with a date (in which case function should be something like setActiveDate(result.dayNumber) and condition will switch to activeDate === result.dayNumber) or even slightly more advanced options like
setActiveDate(`${result.dayNumber}-${result.month}`)
if you really need it.
PS (some advices):
- I would also recommend avoid using so much in-line styling (is not generally a good practice). You can also try classNames - a JavaScript utility for conditionally joining classNames together.
- You can
return nullinstead ofreturn <></>. Also you don't really need theelsestatement before the return (if it will go on the if it will return the value so it will naturally stop the execution. So you can just write the second return without theelse)
You can also slightly improve variable naming ( especially result part ) and the use of const (fontsLoaded and result variables doesn't get reassigned so you can just use const for them as well)

