Home > OS >  track boolean state of each element in array and change styles if active react
track boolean state of each element in array and change styles if active react

Time:01-29

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.

enter image description here

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:

  1. 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.
  2. 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):

  1. 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.
  2. You can return null instead of return <></>. Also you don't really need the else statement 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 the else)

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)

  •  Tags:  
  • Related