What I've Coded This Week (Week 3—WWCode '100 Days of Code' Challenge)

Bianca Aspin - Feb 14 - - Dev Community

Cover Image: Confused emoji wondering why the calendar arrows show up on the mobile view (left) of my React Native app but are missing on the web view (right).

This week ended up being pretty frontend heavy, so while I didn't get anything done in Python land, I did spend a lot of time with JavaScript and CSS, with some more React Native troubleshooting (a recurring theme so far in these posts) thrown in.

Quick Links

React Native—The Case of the Missing Arrows in React Native Calendars

In my last update, I mentioned that I would be working with the 'React Native Calendars' library to build out a calendar tracker for the 'random acts of kindness' app my friend and I are working on. Little did I know that, without even doing anything to modify the default <Calendar> component, I would already have debugging to do. The forward and back arrows to change months were displayed on the mobile view but not the web view.

Comparison of mobile view (with calendar arrows rendered) and web view (without calendar arrows rendered)

I found a stale GitHub issue about the missing arrows and saw that another user had success unearthing the arrows by modifying the arrow's height and width within the component's theme (the working theory being that, because there was no height or width explicitly set for the images, they weren't rendering), so I tried this for myself:

import { View } from 'react-native';
import { Calendar } from 'react-native-calendars';

function CalendarView() {

    return (
        <View>
            <Calendar 
                theme={{
                    arrowHeight: 50,
                    arrowWidth: 50
                }}
            />
        </View>
    )
}
Enter fullscreen mode Exit fullscreen mode

The result looked oddly blurry.

Calendar with blurry arrow buttons

Upon inspecting the page to figure out why that might be, I found out that the arrow icons are PNG files. This is what the original image looks like (you may want to get out your magnifying glass!):

Small right arrow which is the default arrow image used in React Native Calendars

To get around this, I took the suggestion of another user in the issue thread to create custom <Arrow> components, utilizing SVG icons from the React Native Vector Icons library.

import { View } from 'react-native';
import { Calendar } from 'react-native-calendars';
import Icon from 'react-native-vector-icons/MaterialIcons'

function CalendarView() {

    const leftArrow = <Icon 
        name="keyboard-arrow-left"
        size={30}
        color='#62BEC1'
    />

    const rightArrow = <Icon
        name="keyboard-arrow-right"
        size={30}
        color='#62BEC1'
    />

    return (
        <View>
            <Calendar 
                renderArrow={(direction) => {if (direction == "left") return leftArrow;
                                if (direction == "right") return rightArrow;  
                            }}
            />
        </View>
    )
}
Enter fullscreen mode Exit fullscreen mode

Unlike PNG files, SVG files can be resized without losing resolution, which we need here. (Check out this helpful comparison of PNG vs. SVG from Adobe for more info.)

Here's what the calendar looks like now:

Web view of calendar with arrow vector icons rendered

That's more like it! Next up with this project, I'll be doing more styling and customizations and working out some logic to keep track of the days users complete an act of kindness.

JavaScript—JavaScript30 Project #3: CSS Variables

The third project in Wes Bos's JavaScript30 course was an intriguing exercise that introduced me to a concept I was as yet unfamiliar with: CSS variables, also known as custom properties.

CSS Variables Project GIF, showcasing sliders which dynamically update the spacing and blur of the image, as well as a color picker to update the color of the border and text

These handy variables allow you to update multiple properties simultaneously with JavaScript. Unlike the variables in the Sass library that Wes briefly mentioned in the lesson intro, which are defined when a page is compiled, regular CSS variables can dynamically update as a user interacts with the page.

Before learning about CSS variables, here is how I would have written the CSS to match the color of some text with the background behind an image on the same page.

.hl {
    color: #ffc600;
}

img {
    background: #ffc600;
}
Enter fullscreen mode Exit fullscreen mode

Then, if I wanted to change that CSS based on the value chosen from the color input selector on the page, I would need to update both the text and the background separately with JS. I'd need to select each element that needs to be updated, as well as the input, from the DOM, and attach an event listener to the input to watch for changes to the color selection and trigger a handler function. The handler would update the text color and background separately.

const text = document.querySelector('.hl')
const image = document.querySelector('img')

const input = document.getElementById('base')
input.addEventListener("input", (e) => handleColor(e))

function handleColor(e) {
    text.style.color = e.target.value
    image.style.background = e.target.value
}
Enter fullscreen mode Exit fullscreen mode

While this isn't so bad with just two elements being updated, it grows in repetitiveness as more elements need to be changed at once.

With CSS variables, we can pull that common value out by defining a variable for it in the root of the document (set to the default value) and then pointing to that variable next to each of the elements sharing it using var(--variable).

  :root {
    --color: #ffc600;
  }

  .hl {
    color: var(--color);
  }

  img {
    padding: 10px;
    background: var(--color);
  }
Enter fullscreen mode Exit fullscreen mode

Now, instead of using JavaScript to change the value for each element individually, we just need it to update the root value. Then, elements referencing that value will also be updated.

const input = document.getElementById('base')
input.addEventListener("input", (e) => handleColor(e))

function handleColor(e) {
    document.body.style.setProperty('--color', e.target.value)
}
Enter fullscreen mode Exit fullscreen mode

Simplifying this code makes it much easier to create one master event handler for updating numerous elements on the page based on various user interactions, as I eventually did for this exercise. The id in this case refers to the input element ('spacing', 'blur', and 'base'), which, if named similarly to the variables, makes selecting the correct value to update simple with string interpolation.

function handleChange(e) {
    id = e.target.id
    value = e.target.value
    if (id === "base") {
        document.body.style.setProperty(`--${id}`, value)
    } else {
        document.body.style.setProperty(`--${id}`, `${value}px`)
    }
}
Enter fullscreen mode Exit fullscreen mode

You can check out the code and finished product for Project #3 on GitHub.

A Note on the 'Input' Event

I used the input event when setting my event listeners. I was initially confused by Wes's approach of adding separate event listeners for mousemove and change events on the page inputs. Looking closely at the MDN reference for "input", though, I realized that the input event type is a new addition as of March 2023. Because it's new, someone using an older device or browser version may have issues getting the page to work as intended.

JavaScript—JavaScript30 Project #4: Array Cardio (Day 1)

This project was, as promised by the title, a great workout and refresher on the various array methods, including .filter(), .map(), .sort(), and .reduce().

These exercises were an excellent opportunity for me to go back and review what gets returned by each of these methods.

  • .filter(): returns a shallow copy of the original array containing the filtered values.
  • .map(): returns a new array containing the 'mapped' elements of the original array.
  • .sort(): returns the same array, sorted in place.
  • .reduce(): returns the accumulated/aggregated value resulting from iterating through the array (the format of which will vary depending on how you've configured it; one of the reduce exercises here returned an integer value; the other one an object with the tallied appearances of each 'key' element in the original array).

The only one of these methods I haven't used somewhere before was reduce(), and at first, I was a little intimidated. However, I could quickly see its benefits once I took the time to slow down and understand how it works.

Here is how I would have written out Question 4 () before learning about .reduce():

// Array.prototype.reduce()
// 4. How many years did all the inventors live all together?
function totalLifespan(inventorArray) {
    let totalLifespan = 0
    for (let inventor of inventorArray) {
        totalLifespan += (inventor.passed - inventor.year)
    }
    return totalLifespan
}
const totalYears = totalLifespan(inventors)
console.log("Question 4:", totalYears)
Enter fullscreen mode Exit fullscreen mode

With .reduce(), I was able to streamline this code quite a bit! I created a callback function, lifespan, that would return the running total plus the current inventor's lifespan, passing that down the line until we reach the end of the 'inventors' array.

function lifespan(total, inventor){
    return total + (inventor.passed - inventor.year)
}
const totalYears = inventors.reduce(lifespan, 0)
console.log("Question 4:", totalYears)
Enter fullscreen mode Exit fullscreen mode

You could even write that callback inline using an arrow function.

const totalYears = inventors.reduce((total, inventor) => {
    return total + (inventor.passed - inventor.year)
}, 0)
console.log("Question 4:", totalYears)
Enter fullscreen mode Exit fullscreen mode

You can check out the code and finished product for Project #4 on GitHub.

Responsive Design—Kevin Powell's 'Conquering Responsive Layouts' (Week 1)

This past week, I started working through Kevin Powell's 'Conquering Responsive Layouts' course. I'm coming in with some basic familiarity with what it means for a website to be responsive. For instance, I know that adaptable formatting and predictable behavior between devices are vital for accessibility. Kevin's YouTube channel has managed to get me out of multiple CSS jams before, so I figured that this (totally free!) course would be enlightening. One week in, I've already learned a lot.

GIF demonstrating a responsive header created as part of Week 1 project. The heading text reads "Responsive Layouts Don't Need to Be A Struggle". Underneath some placeholder text is a 'I Want to Learn' button.

This first week, we reviewed a few foundational concepts for responsive layouts. During the first lesson, Kevin reiterated a point I'd seen him make in another video ('5 simple tips to making responsive layouts the easy way') that I watched last year while taking some initial steps to make my 'Accessible Parks' app more responsive: HTML is, by default, responsive. The decisions we make with CSS rules we add on top of that HTML are what make it unresponsive. There are two big offenders here in particular:

  • Fixed widths: Setting the width property in pixels makes it challenging to account for the wide variety of screen sizes that your layout might appear on and sets you up for having to create media queries that still won't be able to perfectly match the behavior you want. Setting width with percentages instead will remove that guesswork.

    • max-width: To account for larger screens where you don't want your layout to stretch too far, you can set the max-width property using pixels.
      • This is helpful because, it turns out, people have a hard time reading long, continuous lines of text stretching from one end of a big screen to the other; it makes it harder to keep track of where we are, and we don't want to have to move our heads to keep reading! This article from the Baymard Institute gives a little more background on line lengths and readability: Readability: The Optimal Line Length
  • Heights: It's better to avoid assigning a height property and let the width and the content within the element determine the height of the container. That way, you won't run into situations where the text overflows or gets truncated. You can still add more height using padding.

Over the next week, we'll dive into another area I've worked with before and am excited to gain better mastery of: Flexbox!

Looking Ahead

That's a wrap for this week!

Here's what I'll be working on until my next post:

. . . . . . . .