Bytes #24 - The keys to the universe

The keys to the universe

Issue #24.November 30, 2020.2 Minute read.

Not sure why (🍗?), but this was a slow news week which means this will be a smaller issue than normal.

OK, no more promotion until next year. Pinky promise.


TWIH -- Svelte turns 4

Svelte turns 4

HAPPY HAPPY BIRTHDAY, FROM ALL OF US TO YOU

While we were stuffing our faces with pie last Thursday, we paused to give thanks for Svelte, which was first released 4 years ago on Thanksgiving.

When creator (and part-time shampoo model) Rich Harris first announced Svelte back in 2016, he referred to it as "a framework without the framework." That's a very meta way of saying that Rich believed that frameworks were better for structuring your thoughts than structuring your actual code, because of how a framework's bloat would often slow down applications.

So Rich dreamed up a ~~brave~~ svelte new world where the framework didn't run in the browser, but instead converted your code into lower-level vanilla JavaScript that didn't need to ship a runtime with it. That way, you could still have the benefits of a framework, but your app would be lighter and faster.

Fast forward 4 years and that's still the driving philosophy behind Svelte, along with these 3 main selling points that have emerged:

  1. No virtual DOM -- because Svelte manipulates the DOM directly.

  2. Write components in HTML, CSS, and JavaScript without boilerplate.

  3. Bring "true reactivity" to JavaScript without state management libraries.

The Bottom Line

After 4 years, Svelte still sits somewhere in between "Hipster Devs Only" and "Promising Paradigm Shift" on the JavaScript framework popularity spectrum. It's a highly respected project with a loyal following, but (objectively) still hasn't achieved a lot of mainstream adoption.

So what's next for Svelte?

Rich and the team are focused on improving the developer experience, making it a lot easier to get started, while also increasing the framework's versatility.

We're excited to see what's in store for the next 4 years, and we'll check in again on Thanksgiving 2024.


Cool Bits

  1. Speaking of Svelte, Rich Harris and Evan You went on last week's Undefined Podcast to argue to the death about Svelte vs. Vue. (K fine, it was just a respectful discussion.)

  2. We released Understanding React's useReducer Hook if you want to impress all your coworkers and join team #neveruseState for the status signalling it brings.

  3. Timebomb is a cross-language library that fails loudly if a TODO has not been completed before a deadline you set. Because we could all use a little more stress around the holidays.

  4. Next.js just released a static site generator called Nextra. I guess Nextby was already taken.

  5. Twin.macro blends the magic of Tailwind with the flexibility of css-in-js at build time.

  6. Danilo created Naming My Function, which is basically a Buzzfeed quiz that helps you with the most difficult thing about programming.

  7. tinyhttp just released v1.0 of its speedy, Express-like framework. Written in TypeScript, compiled to native ESM, and uses the bare minimum amount of dependencies.

  8. Vadim did a 4-hour livestream on cloning Twitter Fleets with React Native. Fun fact: Twitter called them "Fleets" because Jack Dorsey is slowly descending into madness like Sweeney Todd -- the Demon Barber of Fleet Street.


JS Tip - .reduce

.reduce holds the keys to the universe. If you master it, you'll be able to do pretty much anything you want with arrays. Before you even look at the API, it's important to understand why .reduce exists. The idea of .reduce is that you can take an array and transform it into anything else - another array, an object, an integer, literally anything. Why would you ever want to do that? Look at every single example on this whole page. In each one, we're taking an array and transforming it in some way - mostly to another array. Let's look at some other common ways you'd transform an array.

[1,2,3] -> sum-> 6

---

[
 { name: 'Tyler', age: 28},
 { name: 'Mikenzi', age: 26},
 { name: 'Blaine', age: 30 }
] -> Just the names -> ['Tyler', 'Mikenzi', 'Blaine']

---

[
 { name: 'Tyler', age: 28},
 { name: 'Mikenzi', age: 26},
 { name: 'Blaine', age: 30 }
] -> Length and age count -> { users: 3, ageTotal: 84}

---

[
  { id: 1, stars: 13, text: 'Turns out "git reset --hard HEAD^" was a terrible idea.' },
  { id: 2, stars: 87, text: 'Tech conferences are too expensive.' },
  { id: 3, stars: 51, text: 'Clean code is subjective. Optimize for deletion.' },
  { id: 4, stars: 19, text: 'Maybe the real benefit of open source was the friendships we made along the way?' },
]
  -> Remove the stars property ->
[
  { id: 1, text: 'Turns out "git reset --hard HEAD^" was a terrible idea.' },
  { id: 2, text: 'Tech conferences are too expensive.' },
  { id: 3, text: 'Clean code is subjective. Optimize for deletion.' },
  { id: 4, text: 'Maybe the real benefit of open source was the friendships we made along the way?' },
]

Here's how I think about whether I should use .reduce or not.

1) Am I transforming an array into another array
just by removing some elements? Use .filter

2) Am I transforming an array into another array? Use .map

3) Am I transforming an array into something other than another array? Use .reduce

Now that we understand what .reduce is used for, let's take a look at the API. Don't worry if this is confusing, with great power comes great initial confusion. Google "reduce JavaScript" and read the first two pages of results. It'll be worth it - promise.

I'll first show you how to accomplish our goal of summing up an array of number into a single integer, then we'll walk through it.

function sum (arr) {
  return arr.reduce((total, num) => {
    return total + num
  }, 0)
}

sum([1,2,3]) // 6
sum([5,5,5]) // 15

Remember, the goal here is to take the array that's being passed into the sum function and transform it into a single integer, which is the summation of all the numbers in the array.

The first thing you'll notice is that we pass .reduce two arguments. The first is a function that will be invoked for every element in the array. The second is what we'll call the "initial value". In our example, because we're adding all the numbers together, we want the initial value to be 0 (so we don't run into any NaN problems). If we were creating a new object, the initial value would be an empty object. If we were creating an array, it would be an empty array.

Next, we need to figure out what the parameters are for the function we pass to .reduce. In our example, we named them total and num. Remember, this function is going to be called for each element in the array. The reason we named it num is because we're reducing over an array full of integers and for each iteration, num is going to be whatever the number is in the array. We can see this in the example below.

function sum (arr) {
  return arr.reduce((total, num) => {
    console.log(num)
  }, 0)
}

sum([1,2,3])
// 1
// 2
// 3

That makes sense. The next thing we need to figure out is total. This is where it gets a little mind-bendy. In our example, total is going to initially be 0, since that's what we set our initial value to. After that, total is going to be whatever the previous iteration returned. We can see this clearly in the example below.

function sum (arr) {
  return arr.reduce((total, num) => {
    console.log(total)
    return Date.now()
  }, 0)
}

sum([1,2,3])

The first time our callback function runs, it logs 0 to the console. Again, that's because we set the initial value to 0. Then, for each new time the function runs, we get a timestamp in the console because that's what we're returning.

Now let's take this knowledge and look back at our initial solution.

function sum (arr) {
  return arr.reduce((total, num) => {
    return total + num
  }, 0)
}

sum([1,2,3])

The very first time the callback function runs, total will be 0 and num will be 1. Then, the next iteration, total will be 1 and num will be 2. The reason total is one is because we previously returned 0 + 1. Then, total will be 3 and num will be 3. Then, there are no more elements in the array so what gets returned is 6. We can see this in the diagram below.

Initial Value: 0

First iteration:
  total: 0
  num: 1

Second iteration:
  total: 1
  num: 2

Third iteration:
  total: 3
  num: 3

No more elements in the array, return 3 + 3 which is 6.

Let's look at the example where we convert an array of objects into another object.

[
 { name: 'Tyler', age: 28},
 { name: 'Mikenzi', age: 26},
 { name: 'Blaine', age: 30 }
] -> Length and age count -> { users: 3, ageTotal: 84}

First, what do we want the initial value to be? We want it to be an object with a users property as well as an ageTotal property, both set to 0.

function getUserData (users) {
  return users.reduce(() => {

  }, { users: 0, ageTotal: 0 })
}

Now we need to figure out what each iteration looks like. We know what we want to return is the initial object, adding 1 to the users property and adding whatever the user's age is to the ageTotal property.

function getUserData (users) {
  return users.reduce((data, user) => {
    data.users += 1
    data.ageTotal += user.age

    return data
  }, { users: 0, ageTotal: 0 })
}

const users = [
 { name: 'Tyler', age: 28},
 { name: 'Mikenzi', age: 26},
 { name: 'Blaine', age: 30 }
]

getUserData(users) // { users: 3, ageTotal: 84 }

Impressive, yeah? Odds are this is still a bit fuzzy. The best thing you can do is take an array, and practice transforming it into anything you can think of.

Join Bytes

Delivered to 105,434 developers every Monday