The Ang-eissance

Issue #238.November 9, 2023.2 Minute read.
Bytes

Today’s issue: “Simplifying” React state management, building local apps for fun, and employing Julia Stiles as the unofficial React Query spokesperson.

Welcome to #238.


Eyeballs logo

The Main Thing

A guy dressed in a black robe at a renaissance fair looking very pleased

When you smell those fresh turkey legs at the Angular Renaissance Fair

The Ang-eissance

Angular 17 just launched yesterday, capping off a period that the core team calls the “Angular Renaissance.”

Sadly, they didn’t break out the harpsichord and oil paints for the launch party — but they did unveil a brand new, gradient-tastic Angular logo and a sleek new docs site, Angular.dev.

v17 builds on Angular’s past couple of major releases, which kicked off the Ang-eissance by introducing transformative new features like signal-based reactivity, standalone components, and more.

Yesterday’s release doesn’t pack quite as many impactful features, but there are definitely still a few highlights worth checking out:

  • New built-in control flow that offers better type checking, significant performance improvements, and more intuitive syntax. It’s kind of like regular JavaScript with a bunch of @ symbols, which makes me wonder when they’re going to drop the @channel directive to really screw up your Slack etiquette.

  • Deferrable views are similar to React’s suspense, making it easy to manage loading and error states while lazy loading your code.

  • Hybrid rendering now allows you to pre-render certain pages at build time (SSG) and server render (SSR) other ones using the new @angular/ssr package.

Bottom Line: Angular’s syntax is evolving to look more like Vue and React, but it’s still staying true to its batteries-included ethos by owning the meta-framework layer of rendering, routing, etc.

Taking a more opinionated approach has worked pretty great for the last 13+ years, and if the Angular core team continues to innovate like this, we’ll probably still be writing about it for another 13 years.

        

spamspy logo

Our Friends
(With Benefits)

The Captain Planet kids putting their rings together to summon Captain Planet

With all our spam combined, we can save the internet

SpamSpy is the future of spam fighting

It’s a community-driven spam blocker that works by combining all our spam data together to create an AI-powered solution that’s constantly evolving.

That lets it stay one step ahead of bots and spammers, instead of just reacting to them.

And right now, they’re gearing up to launch SpamSpy v2, and holding a raffle that will let you get early insider access 👀.

Here’s how it works:

  1. Subscribe to the SpamSpy API on RapidAPI.

  2. Subscribe to the SpamSpy Newsletter.

  3. Join the SpamSpy Discord, accept rules by reacting to the post in the #rules channel.

  4. Go to the bot channel (#🔎spy-bot🔍) type /auth and link the bot to your RapidAPI key.

Try it out for yourself, and see why SpamSpy is the future of spam fighting.


Spot the Bug logo

Spot the Bug

Sponsored by Clerk

Clerk is the go-to tool for setting up auth in any React app. It’s incredibly simple, easy to scale up, and has a phenomenal free tier. Win-win-win.

function logPropertyUpdates(target) {
  return new Proxy(target, {
    set(target, property, value, receiver) {
      console.log(`Property "${property}" changed to "${value}"`);
      return Reflect.set(target, property, value, receiver);
    },
  });
}

const user = logPropertyUpdates({
  name: "Lew",
  details: {
    age: 24,
    country: "USA",
  },
});

user.name = "Kareem";
user.details.age = 25;

Cool Bits logo

Cool Bits

  1. Timothée asks the question of our time in his article called, React Server Components without a Framework? It helps demystify RSC by walking through what they’re doing under the hood. Tim is currently looking for a job too, so someone should hire him.

  2. Retool AI gives you pre-built blocks that can easily connect to any LLM and your own business data, so you can easily build a custom AI app in an afternoon. Try it out for free. [sponsored]

  3. Ink & Switch released automerge-repo, a toolkit for building local-first applications. It’s never been easier to build an app that no one will use 🙏.

  4. In our Story of Next.js video, we broke down all of the historical context behind Next, which will help you understand why it became the dominant tool it is today.

  5. Jacob Paris wrote about How to generate dynamic OG images with Remix, which means we get to see Mark Dalgleish’s face more as a byproduct ❤️.

  6. The Causal team wrote about how they Simplified React state management for their application by building their own framework from scratch. More power to you, but I feel like we have different interpretations of “simplify.”

  7. Odoo just launched v17 of its open-source business platform and framework that makes it easy to build all the business functionality you need for your clients. And it now offers both self-hosted and managed hosting solutions for ultimate flexibility. [sponsored]

  8. TkDodo wrote about Why you want need React Query. “Am I that transparent? I want you, I need you, oh baby oh baby.”

  9. Cami.js is a minimalist and flexible toolkit for interactive islands and state management with no build step.

  10. Adam Wathan gave a 30-minute talk at Rails World about Tailwind CSS called, It looks awful, and it works. That’s the exact same thing my middle school drama teacher said after I showed her my interpretive dance to She Wolf by Shakira.


Spot the Bug logo

Spot the Bug: Solution

Sponsored by Clerk

ES6 Proxies are not recursive by default. In the above example, the user object is wrapped in a Proxy, but the details property is not. Therefore, when the user.details.age property is updated, the Proxy is not triggered.

To fix this, we can make the Proxy recursive:

function logPropertyUpdates(target) {
  if (typeof target === "object" && target !== null) {
    return new Proxy(target, {
      get(target, property, receiver) {
        const value = Reflect.get(target, property, receiver);
        return logPropertyUpdates(value);
      },
      set(target, property, value, receiver) {
        console.log(`Property "${property}" changed to "${value}"`);
        return Reflect.set(target, property, value, receiver);
      },
    });
  }
  return target;
}

const user = logPropertyUpdates({
  name: "Lew",
  details: {
    age: 24,
    country: "USA",
  },
});

user.name = "Kareem";
user.details.age = 25;