Frontend Armory https://frontarm.com/ Level up your JavaScript through interactive exercises and examples. Thu, 10 Sep 2020 00:00:00 GMT http://blogs.law.harvard.edu/tech/rss Frontend Armory Copyright Frontend Armory <![CDATA[Frontend Armory is now Free!]]> https:/frontarm.com/james-k-nelson/demonetization/ https:/frontarm.com/james-k-nelson/demonetization/ Thu, 10 Sep 2020 00:00:00 GMT

So it’s been about a year since the last major update of Frontend Armory and… not particularly much has happened in the meantime. My life outside of the internet has gone through changes which have left me with less time than I’d like to work on content — about a day per week to be exact. And to be honest, I haven’t used that day a week as effectively as I’d like. The result being, well, nothing much of value.

Nothing much of value is a pretty bad look for a subscription-based site, so I’ve just put through a refund for all subscription fees paid between now and November 29 last year — which was Black Friday, and occurred before I made the last major update.

I’ve also made all of Frontend Armory’s content free, at least for now. It’s a little out of date, but there’s still a lot to learn from it. Here’s a few of my favorites that used to be behind the paywall:

I may add more paid content in the future, but if I do, it definitely won’t be subscription-based. Honestly, using a subscription model for this project was a mistake grounded in overly optimistic predictions of the amount of revenue… and the stability of React’s API. I’ll write about that another day, or actually, fuck it, I’ve just written about it at my blog: React: it’s technically backwards compatible!.

#Where to from here

First, a break. But I do still want to teach programming — at least from what I can see, it’s one of the few ways to get a leg up in this world. And besides, it’s damn interesting.

I want to finish Vouch, and the React + Bacon course too. If you read my rant on React’s backwards compatibility, you might be surprised to hear that, but yep, I’m still planning on using React. React isn’t what it was, but it’s still a damn good tool. It’s a little like ordering a pizza and getting a steak.

One thing I’ve learned over the past year is that I can’t teach everything. My big issue with Vouch, React + Bacon was that I wanted to teach everything from the ground up. I wanted to teach people to build their own router, their own authentication, they’re own design system, etc. And… while it may well be possible for an experienced engineer to build an entire app from scratch, teaching it is another matter. I wrote a lot of drafts and code that never saw the light of day because the scope was just too large.

So, here’s my current goal: I want to create a useful app with working payments, but which you can build in a weekend. Then I want to live stream myself building the app, buying the domain, and deploying it — all in one day-long session. I want the app to be online, making money, providing a real service. And then I want to teach you to make that app.

I’ve actually been working on this the past few months — basically since I quit Twitter. I thought it’d take me a month or two to get to the point where I can do the stream. It’s taking longer, as it always does. But I’m happy with the direction, and I’m making slow but steady progress. You can see some of it here. For now, I’m going to take a bit of a break — but I do think you’ll hear more about the project at some point in the future.

Until then, thanks for reading :)

]]>
[email protected] (James K Nelson)
<![CDATA[What the this? 5 simple rules to tame JavaScript's most confusing keyword]]> https:/frontarm.com/james-k-nelson/what-the-this/ https:/frontarm.com/james-k-nelson/what-the-this/ Fri, 15 May 2020 00:00:00 GMT

this may well be the most confusing part of JavaScript you’ll run up against — it sure is for me. And what’s worse, unlike other confusing things (like the arguments fake-array), there’s no modern substitute for it! You need this for classes, and thus for many modern JavaScript libraries. You’re kinda stuck with it.

It’s no wonder then that I recently received an e-mail with a question about this. In particular, the reader wanted some help understanding the below block of code from my article When to use arrow functions with React:

Within this render function, the call to handleClick is preceded by this.. The this on line 4 refers to the component instance, so shouldn’t the this on line 7 point to the component instance too?

class BrokenButton extends React.Component {
  render() {
    return (
      <button onClick={this.handleClick} style={this.state}>        Set background to red
      </button>
    )
  }

  handleClick() {
    this.setState({ backgroundColor: 'red' })  }
}

Firstly, thanks for the great question! This is something that most JavaScript developers have struggled with at some point — myself included. To really understand what’s going, there’s no substitute for trying things out, so later in this article I’m going to walk you through a bunch of live demos (after introducing the 5 rules that’ll help you understand this). But I’m getting ahead of myself! Let me start by answering the question:

If a call to handleClick is preceded by this., then the value of this within the function will behave as you expect. The issue is, the above example never actually calls handleClick().

To put it another way: calling this.handleClick() will change the function’s behavior, setting the value of the this keyword within the handleClick function. In contrast, passing this.handleClick just passes the function as a value — without changing the behavior at all.

Confused? You’re not alone. But keep reading — we’ll get to the bottom of this together.

#It’s all in the call

When working with JavaScript functions, the value of this depends on the way in which the function was called — as opposed to the way in which the function was defined.

This can result in some truly boggling behavior. For example, try uncommenting the final two lines in the below example. Like actually try it out. Seeing is believing. I’ll wait here.

const robot = { 
  dream: "kill all humans",
  sleepTalk() {
    console.log(`Hey baby, wanna ${this.dream}?`)
  }
}

robot.sleepTalk()

// // You'd think this would do the same thing as the line above.
// const robotSleepTalk = robot.sleepTalk
// robotSleepTalk()

Did you give it a shot? Great! So you’ll have noticed that while calling robot.sleepTalk() prints a classic line from Futurama… calling exactly the same function a couple lines later causes the app to die.

So what’s going on? Let’s see if you can’t figure it out yourself, using the 5 rules of this.

#The 5 rules of this

The value of this in a JavaScript function can vary based on how the function was called. There are far too many rules to list them all right here, but 99% of situations are covered by just three rules:

  1. When a function is called as a method of an object, e.g. obj.someFunction(), the value of this within that function will be the object on which it was called.
  2. When a function is called using its call() or apply() methods, the value of this inside the function is provided as the first argument to call() or apply().
  3. When a function is called by itself (i.e. without a leading .), the value of this will either be undefined in strict mode, or the global object (e.g. window) outside of strict mode. But you’re probably in strict mode, so it’s probably going to be undefined.

There are two important exceptions to these rules:

  1. You can use a function’s bind method to return a version of a function where this will always equal the first argument to bind.
  2. The value of this within an arrow function will always equal the value of this at the time the function was created.

These rules and exceptions are a bit of a mouthful, so let’s take a look at some live examples.

#Methods and this

The simplest and most obvious way for a function to get a value for this occurs when the function is called as a method. In this case, this is set to the object on which it was called.

class Counter {
  constructor(initialCount = 0) {
    this.count = initialCount
  }

  increment() {
    return this.count += 1
  }
}

const counter = new Counter()

console.log('initial count', counter.count)
console.log('after increment', counter.increment())
console.log('and again', counter.increment())

Keep in mind that it doesn’t matter how a function is defined — only how it is called. This means that there are many different ways to create a counter with the same API as above:

function increment() {
  return this.count += 1
}

const counter1 = {
  count: 0,
  increment,
}

const counter2 = {
  count: 0
}
counter2.increment = counter1.increment

console.log('counter1', counter1.increment(), counter1.increment())
console.log('counter2', counter2.increment(), counter2.increment())

#this on plain functions

When you call a function by itself in a strict-mode application, this will be undefined.

function increment() {
  return this.count += 1
}

console.log(increment())

Obviously, it’s unlikely you’re ever going to write code like the above. But this rule can still cause you all sorts of grief, especially when this rule is applied to functions that were designed to be called as methods.

For example, say you pass a counter instance’s increment method to a setTimeout() function.

class Counter {
  constructor(initialCount = 0) {
    this.count = initialCount
  }

  increment() {
    this.count += 1
    console.log('value after increment', this.count)
  }
}

const counter = new Counter

counter.increment()
setTimeout(counter.increment, 100)

See how the call to increment by setTimeout() doesn’t behave as you’d expect? This is because internally, setTimeout() doesn’t have access to the counter object — it only has access to the increment function. As a result, increment is called by itself, and this is undefined for the duration of that call.

#this on arrow functions

When using arrow functions, you’ll find that the value of this is fixed to whatever it was when the function was defined. When the function is created at the top level, this will usually be undefined. But where things get interesting are when you define arrow functions within other functions. In this case, the value of this within the arrow function will reflect the value of this within the function that created it.

One place where arrow functions come in handy is class constructors. Any arrow functions defined in a constructor will always have a value of this that points to the class instance, no matter where they’re called from — making them perfect for event handlers.

class Counter {
  constructor(initialCount = 0) {
    this.count = initialCount
    this.increment = () => this._increment()
  }

  _increment() {
    this.count += 1
    console.log('value after increment', this.count)
  }
}

const counter = new Counter

counter.increment()
setTimeout(counter.increment, 100)

Arrow functions are also great for event handlers in React’s class components, as they reduce the mental overhead for accessing instance methods like setState().

#Specifying this using bind, call and apply

If you need to force a specific value of this but can’t use an arrow function, then bind, call and apply are your friends. These functions allow you to specify a function’s arguments and this value programmatically.

I won’t go into too much detail on how these work — if you’re interested, you can follow the above links to read the details on MDN. For good measure though, here’s a demo using all three:

function increment() {
  return this.count += 1
}

const counter = { count: 0 }

increment.bind.call(increment, counter).apply()

console.log('did it increment?', !!counter.count)

As bind, call and apply are themselves functions… well, you can use them on each other. But please, don’t do this at home (or especially at work).

#The this quiz

Now that you’ve seen this in action, let’s take another look at the broken dreaming bending robot:

const bendingRobot = { 
  dream: "kill all humans",
  sleepTalk() {
    console.log(`Hey baby, wanna ${this.dream}?`)
  }
}

bendingRobot.sleepTalk()
const bendingRobotSleepTalk = bendingRobot.sleepTalk
bendingRobotSleepTalk()

Now do you know why the last line throws an error, while calling bendingRobot.sleepTalk() works as expected? Have a think about it, and then check your answer below.

Spoiler

this doesn’t care about where sleepTalk was defined — it only cares about how it was called. In the case where it’s called using robot.sleepTalk(), the value of this will be robot. However, when called as a bare function, this will be undefined.

#Exercise: fixing the React component

Let’s finish up by taking another look at the broken React component from the start of this article. Now that you’ve learned about the different ways to control the value of this, can you fix the component so that clicking the button changes the background color?

import React from 'react'

export class App extends React.Component {
  render() {
    return (
      <button onClick={this.handleClick} style={this.state}>
        Set background to red
      </button>
    )
  }

  handleClick() {
    this.setState({ backgroundColor: 'red' })
  }
}

How’d you go — were you able to make the button work?

Keep in mind that there’s no right ways to do this — I’ve provided one solution on the solution tab, but it’s by no means the only one. If you come up with another solution, I’d love to see it — you can let me know with a tweet!

#The best approach to this?

So now that you know all about this, I want to finish up by discussing the best approach to using it:

In my opinion, the best use of this is no use of this.

At best, this is confusing. At worst, it can be the cause of obscure and unpredictable bugs. If you have the choice, the easiest thing to do is to just avoid it. And luckily, if you’re using React, hooks make it easier than it’s ever been to avoid this completely!

With this in mind, in a future article, I want to dive into the workings of a custom hook from one of my production codebases. And I’m looking for your help to decide which one! Here are the options:

  • useLatestSnapshot() - a hook for integrating with Firebase, simplifying access to the latest Snapshot of a Firestore Document or Query.
  • useMediaQuery() - a hook that returns a boolean reflecting whether the browser currently matches the given media query.
  • usePopupTrigger() - a hook that manages the state of popup menu, independent of its presentation.

If you’d like to have a say in which of these I write about, it’s easy — just send a quick email or tweet telling me which of the above options you’d like to see. Of course, I’d love to hear any of your other JavaScript questions too! I won’t promise to respond to every message, but I’m always looking for ideas for content that can help give people a leg up. I can’t wait to hear from you — and until next time, happy coding!

]]>
[email protected] (James K Nelson)
<![CDATA[Control Components: reuse react components with pseudo-selectors]]> https:/frontarm.com/james-k-nelson/decoupling-react-pseudo-styles/ https:/frontarm.com/james-k-nelson/decoupling-react-pseudo-styles/ Fri, 08 May 2020 00:00:00 GMT

So you’ve built yourself a <Button> component, and it’s a darn good button at that. It’s got props to configure everything you’d ever need - the label, icon, colors, and even a loading spinner. It has beautiful styles for hover, active and focus states, and it even works well with screen readers.

Your button component can take anything the world throws at it! And then you realize that you don’t actually need a button after all. What you really needed was a link that looks like a button.

Luckily, you can fix this without even resorting to copy and paste! Because after a bit of searching, you stumble across the concept of as props…

#as props (considered harmful)

When you first see an as prop, it can be something of an epiphany. Props can be anything, even components! JSX elements can have variable types!

Here’s what a simple <Button> with an as prop looks like in practice:

import React from 'react'

export function Button(props) {
  const {
    as: Component = 'button',
    className = '',
    icon: Icon,
    label,
    ...rest
  } = props
  
  return (
    <Component className={`Button ${className}`} {...rest}>
      {Icon && <Icon />}
      <span className="label">{label}</span>
    </Component>
  )
}

Make sense? If not, it’s probably worth taking a look at the first few free lessons in my React Fundamentals course — especially the bits on JSX and props. But to give you a two-sentence explanation: the above <Button> component returns an element with a variable type. By default, it uses the string "button" as its type — but by passing an as prop, you can set that to "a", Link, or anything else that strikes your fancy.

If you work with React on a regular basis, you’ll probably have seen as props in the wild. For instance, Styled Components supports them. You might also have seen them used with custom <Button> components, allowing them to be somewhat hackily connected up to your router of choice’s <Link> component (and thus improving response time when clicking the links):

import React from 'react'
import styled from 'styled-components'

export const Button = styled.button`
  align-items: center;
  background-color: transparent;
  border: 2px solid deepskyblue;
  border-radius: 8px;
  color: white;
  display: inline-flex;
  font-family: sans-serif;
  font-size: inherit;
  line-height: 1.4rem;
  margin: 0 4px;
  padding: 8px 12px 8px 4px;
  position: relative;
  text-decoration: none;
  transition:
    border-color 150ms ease-out,
    transform 150ms ease-out;

  &:not([disabled]) {
    cursor: pointer;
  }
  &:not([disabled]):hover {
    border-color: white;
  }
  &:not([disabled]):active {
    transform: scale(0.95);
  }
  &:focus {
    outline: none;
  }
  &:focus::after {
    content: ' ';
    position: absolute;
    left: 2px;
    right: 2px;
    top: 2px;
    bottom: 2px;
    border: 2px solid white;    
    border-radius: 5px;
  }
  &[disabled] {
    opacity: 0.5;
  }
}
`

You saw me make up the word hackily, so now you’re thinking — what’s so hackily about this? Well, assuming you don’t want well-typed components (hint: you do want well-typed components), I guess it does kinda work in this particular case.

But let me throw you a new requirement.

#Active margins

So you’ve got a button, and it’s got beautiful, animated hover styles. You nudge your mouse over the button, and it lights up like a christmas tree.

import React from 'react'
import styled, { keyframes } from 'styled-components'

const rotate = keyframes`
  0% {
    transform: rotate(0deg);
  }
  
  100% {
    transform: rotate(360deg);
  }
`

export const Button = styled.button`
  align-items: center;
  background-color: #223344;
  box-sizing: border-box;
  background-clip: content-box;
  border: 2px solid transparent;
  border-radius: 8px;
  border-top-left-radius: 7px;
  border-bottom-right-radius: 7px;
  color: white;
  cursor: pointer;
  display: flex;
  font-family: sans-serif;
  font-size: inherit;
  justify-content: center;
  height: 40px;
  width: 100px;
  outline: none;
  overflow: hidden;
  padding: 2px;
  position: relative;
  transition: background-color 150ms ease-out, padding 150ms ease-out;
  
  &::before {
    content: '';
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    z-index: -1;
    margin: -40px;
    border-radius: inherit;
    background: linear-gradient(45deg, deepskyblue, fuchsia);
  }
  
  &:hover {
    background-color: #223344CC;
  }
  
  &:hover::before {
    background: linear-gradient(200deg, red, lightgreen) !important;
    animation: ${rotate} 2s linear infinite;
  }
  
  &:active {
    padding: 4px;
  }
  &:focus::after {
    content: ' ';
    position: absolute;
    left: 5px;
    right: 5px;
    top: 5px;
    bottom: 5px;
    border: 1px dotted rgba(255, 255, 255, 0.5);
    border-radius: 2px;
  }
}
`

In fact, this button is looking so darn pneumatic that why wouldn’t we want a whole bar full of them?

import React from 'react'
import styled, { keyframes } from 'styled-components'

import { Button } from './button'
import { PreviousIcon, NextIcon, RefreshIcon } from './icons'

export function App() {
  return (
    <Bar>
      <Button><PreviousIcon /></Button>
      <Button><NextIcon /></Button>
      <Button><RefreshIcon width={18} height={18} /></Button>
    </Bar>
  )
}

const Bar = styled.div`
  background-color: #223344;
  box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.2);
  border-radius: 6px;
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  height: 58px;
  padding: 8px;
  width: 150px;
  z-index: 0;
  
  > * {
    flex: 1;
  }
`

Beautiful. There’s just one problem. When your boss comes along and tests everything on a tiny phone after you’ve been happily developing it on your vintage 2013 15" Macbook Pro and what a beautiful machine it is… well anyway, your boss doesn’t like the fact that he had to press the button 3 or 4 times to finally hit the target. The touch targets are too small. And by golly gosh, he shouldn’t be happy about that — it’s awful for user experience.

Those margins around the buttons? They need to be active. Despite being outside of the button body, they still need to be part of the button control. But it’s not like you can just add margin or padding to your <Button> element — margins are inactive, and padding is internal.

Here’s the problem: your styles and behavior are all defined on one big, monolithic <Button> component. And while as props let you modify the behavior of that styled component, what you really want is two separate components: one which handles behaviors, and a separate one to handle the styles.

#The solution: Control Components

You know how when you render a <button> or an <a>, by default, the browser applies a bunch of styles to make them look like buttons and links?

<p>
  <button>A vanilla HTML button</button>
</p>
<p>
  <a href="#">Followed by a vanilla HTML link</a>
</p>

My thesis is: in the React world, the browser`s default styles are just getting in the way. It’d make far more sense for components like <button> and <a> to be unstyled wrappers, with the button styles rendered as children.

So instead of:

<Button as={Link} href='/' style={{ margin: 8 }}>
  Home
</Button>

You want:

<UnstyledLinkControl href='/'>
  <ButtonBody style={{ margin: 8 }}>
    Home
  </ButtonBody>
</UnstyledLinkControl>

Looks simple enough, right? But there’s a trick: the hover styles for <ButtonBody> need to be activated when the mouse hovers over <LinkControl>. Or <AControl>. Or <ButtonControl>. Or any other control.

As it happens, there are three ways to achieve this: the naive way, the clunky way, and the best way. Let’s take a look at each.

#Styled component selectors

One of the less-known features of the Styled Components library, is that it lets you use your styled components themselves as selectors. Combined with nested styles and the & selector, this means that components can declare styles that’ll only apply when a parent is being hovered over — as in the above example.

For example, here’s how you’d add hover styles for <ButtonBody> that activate when the mouse hovers over an <AControl> or a <ButtonControl>:

export const AControl = styled.a`
  /* ... reset styles ... */
`
export const ButtonControl = styled.a`
  /* ... reset styles ... */
`

export const ButtonBody = styled.span`
  background-color: #223344;

  ${AControl}:hover &, ${ButtonControl}:hover & {
    background-color: #223344CC;
  }
`

Here’s the full example:

import React from 'react'
import styled, { keyframes } from 'styled-components'

import { AControl, ButtonBody, ButtonControl } from './control'
import { PreviousIcon, NextIcon, RefreshIcon } from './icons'

const currentPage = parseInt(
  window.location.search.split('?page=')[1] || 1,
  10
)

export function App() {
  return (
    <>
      <Bar>
        <AControl
          disabled={currentPage === 1}
          href={currentPage > 1 ? `/?page=${currentPage - 1}` : undefined}
          onClick={currentPage === 1 ? (event) => event.preventDefault() : undefined}>
          <ButtonBody>
            <PreviousIcon />
          </ButtonBody>
        </AControl>
        <AControl href={`/?page=${currentPage + 1}`}>
          <ButtonBody>
            <NextIcon />
          </ButtonBody>
        </AControl>
        <ButtonControl onClick={() => alert('refresh!')}>
          <ButtonBody>
            <RefreshIcon width={18} height={18} />
          </ButtonBody>
        </ButtonControl>
      </Bar>
      <h1>Page {currentPage}</h1>
    </>
  )
}

const Bar = styled.div`
  background-color: #223344;
  box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.2);
  border-radius: 6px;
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  height: 58px;
  padding: 0 8px;
  width: 150px;
  z-index: 0;
  
  > * {
    flex: 1;
  }
`

If you try hovering over the buttons on this version of the toolbar, you’ll see that the margins are now active; they cause the inner button’s hover styles to be activated! Of course, this approach doesn’t really solve the problem, because the <ButtonBody> component still needs to explicitly specify each and every control that it can be used with; it’s tightly coupled.

For example, the above <ButtonBody> component only works with standard <a> tags — it doesn’t work with <Link> components from your favorite routing library. And while you could fix this by creating a <LinkControl> component and adding it to the css for <ButtonBody>, it turns out there’s a better way…

#Control Context

One of the neat things about Styled Components it allows your styles to reference a theme object. This is often used to set colors based on a global theme:

const Button = styled.button`
  background-color: ${props => props.theme.buttonBackgroundColor};
`

As it happens, Styled Components also lets individual components merge new values into that theme object, which will apply only for that component’s children.

export const ButtonControl = () => {
  const theme = useContext(ThemeContext)
  const patchedTheme = {
    ...theme,
    // ... merged values
  }

  return (
    <ThemeContext.Provider value={patchedTheme}>
      ...
    </ThemeContext.Provider>
  )
}

By feeding the Control Component’s styled component into context, it becomes possible for child components to create selectors that are specific to whatever control they’re being used in.

For example, here’s the :hover example from before, with the :hover selector being applied to whatever component has been added to the parentStyledComponent property of the theme object:

export const ButtonBody = styled.span`
  background-color: #223344;

  ${({ theme }) => theme.parentStyledControl}:hover & {
    background-color: #223344CC;
  }
`

Here’s a full example taking this approach — I’ve even connected it up to Navi's <Link> component for good measure!

import { route } from 'navi'
import React from 'react'
import styled, { keyframes } from 'styled-components'

import { ButtonBody, ButtonControl, LinkControl } from './control'
import { PreviousIcon, NextIcon, RefreshIcon } from './icons'

export function Page({ currentPage }) {
  return (
    <>
      <Bar>
        <LinkControl
          disabled={currentPage === 1}
          href={currentPage > 1 ? `/${currentPage - 1}` : undefined}
          onClick={currentPage === 1 ? (event) => event.preventDefault() : undefined}>
          <ButtonBody>
            <PreviousIcon />
          </ButtonBody>
        </LinkControl>
        <LinkControl href={`/${currentPage + 1}`}>
          <ButtonBody>
            <NextIcon />
          </ButtonBody>
        </LinkControl>
        <ButtonControl onClick={() => alert('refresh!')}>
          <ButtonBody>
            <RefreshIcon width={18} height={18} />
          </ButtonBody>
        </ButtonControl>
      </Bar>
      <h1>Page {currentPage}</h1>
    </>
  )
}

const Bar = styled.div`
  background-color: #223344;
  box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.2);
  border-radius: 6px;
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  height: 58px;
  padding: 0 8px;
  width: 150px;
  z-index: 0;
  
  > * {
    flex: 1;
  }
`

export default route({
  getView: ({ params }) => <Page currentPage={parseInt(params.number, 10)} />
})

You can see how this pattern opens up a whole new world of possibilities… but you can also see how manually fiddling with context, nested selectors and default styles can get old fast. And that’s why there’s now a package for that!

#React Utilities for Controls

The @retil/control package exports everything you need to start using control components, including:

  • <AControl> and <ButtonControl> components for Styled Components
  • Template functions for active, disabled, focus and hover selectors, which can be used within your styled components and css template strings
  • A higher-order control() function that turns any Styled Component into a context-providing Control Component
  • The raw css strings used to reset the browser default styles

Here’s how to refactor the above example using @retil/control

import {
  ButtonControl,
  active,
  control,
  disabled,
  focus,
  hover,
  resetACSS
} from '@retil/control'
import React from 'react'
import { Link } from 'react-navi'
import styled, { keyframes } from 'styled-components'

const StyledLinkControl = styled(Link)(resetACSS)
export const LinkControl = control(StyledLinkControl)
export { ButtonControl }

const rotate = keyframes`
  0% {
    transform: rotate(0deg);
  }
  
  100% {
    transform: rotate(360deg);
  }
`

export const ButtonBody = styled.span`
  align-items: center;
  background-color: #223344;
  box-sizing: border-box;
  background-clip: content-box;
  border: 2px solid transparent;
  border-radius: 8px;
  border-top-left-radius: 7px;
  border-bottom-right-radius: 7px;
  color: white;
  cursor: pointer;
  display: flex;
  flex: 1;
  font-family: sans-serif;
  font-size: inherit;
  justify-content: center;
  margin: 12px 4px;
  outline: none;
  overflow: hidden;
  padding: 2px;
  position: relative;
  transition: background-color 150ms ease-out;
  
  &::before {
    content: '';
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    z-index: -1;
    margin: -10px;
    border-radius: inherit;
    background-image: linear-gradient(45deg, deepskyblue, fuchsia);
    transition: opacity 100ms ease-out;
    animation: ${rotate} 2s linear infinite;
    animation-play-state: paused;
  }

  ${disabled`
    ::before {
      opacity: 0.5;
    }
  `}
  
  ${hover`
    background-color: #223344CC;

    &::before {
      background-image: linear-gradient(200deg, red, lightgreen);
      animation-play-state: running;
    }
  `}

  ${active`
    ::before {
      opacity: 0.5;
    }
  `}

  ${focus`
    ::after {
      content: ' ';
      position: absolute;
      left: 5px;
      right: 5px;
      top: 5px;
      bottom: 5px;
      border: 1px dotted rgba(255, 255, 255, 0.5);
      border-radius: 2px;
    }
  `}
}
`

The package also exports a bunch of more advanced utilities:

  • A createTemplateHelper() function, in case the default template helpers (e.g. hover) don’t suit your needs
  • A useControlContext() hook that returns the raw Control Context (internally, it’s stored within your Styled Components theme)
  • AControlProps and ButtonControlProps types for TypeScript projects

#Give it a whirl

I’d love to see what you build with @retil/control. I’d also love to show the world — if you give it a whirl, make sure to send a [Pull Request] adding yourself to the apps using @retil/control` section in the README!

One more thing — I want to thank everyone who contributed to the discussion about this idea on Twitter!

Unimplemented.

You might be able to guess from the package name — but @retil/control is the first React Utility that I’ll be publishing under the “retil” brand, and there’ll almost certainly be more. If you’ve got some code and you’re somehow convinced that there’s gotta be a better way of doing it, then you’re in good company. Send me a Tweet, and let’s nut out how to make a utility that can improve everyone’s React experience.

That’s it for today — happy coding! And if I don’t see you on the Twitters, I’ll see you at the next post!

]]>
[email protected] (James K Nelson)
<![CDATA[Is a Redux Store Observable?]]> https:/frontarm.com/james-k-nelson/is-a-redux-store-observable/ https:/frontarm.com/james-k-nelson/is-a-redux-store-observable/ Fri, 01 May 2020 00:00:00 GMT

If you’ve been using JavaScript for a while, then you’ve probably heard of observables. They’re at the core of Apollo Client, Angular JS, and there’s even a proposal to add them to JavaScript itself.

Of course, for many people, the first thing that comes to mind when you hear the word observables is the enormous RxJS library. And because of this, it can seem like observables are big, complicated things. But in truth, they can be as simple as a plain object with a subscribe method.

interface Observable<T> {
  subscribe(onNext: (value: T) => void): () => void
}

While slightly different to the RxJS Observable, the above interface accomplishes exactly the same thing. It says: an Observable is an object with a subscribe() method, that takes an onNext(value) callback, and returns a function (which can be used to cancel the subscription). Simple, right? In fact, if you’ve ever used a Redux store, you might have seen something similar.

#Redux’s Store

When you create a store using Redux’s createStore() function, you’ll get an object with a subscribe() method. In fact, this looks a lot like an Observable’s subscribe() method — but there’s an important difference.

interface ReduxStore {
  subscribe(onChange: () => void): () => void
}

Can you see what the difference is? Check your answer by clicking the spoiler below.

Spoiler

The callback that you pass to a Redux store’s subscribe() method does not receive any arguments!

Where an observable’s subscribe() function notifies you of each value as it occurs, Redux’s subscribe function only tells you that something changed… probably. To find out what changed, you’ll need to call another method on the store object: getState().

interface ReduxStore<T> {
  getState(): T
}

#A trick question

Say that you have an observable, and you want to log every value that it produces to the console. Here’s how you’d do it:

observable.subscribe((value) => {
  console.log(value)
})

Makes sense, right? So the next question is: how would you log every state of a Redux store to the console? Let’s do this as an exercise!

Your task is is to log every state of the below store to the console.

Remember: you can get the current state with store.getState().

You may think that this exercise looks far too simple, but give it a try anyway — you’ll see why when you’re done.

import { store } from './store'

console.log('Your task: log each new store state to the console.')

store.subscribe(() => {
  // TODO
})

for (let i = 0; i < 5; i++) {
  store.dispatch({ type: 'next' })
}

How’d you go? Did you find something odd, where the console displayed every even number between 2 and 10 — twice? Let me explain why.

Spoiler

While index.js only dispatches 5 actions, store.js also has a subscribe() handler — and this one dispatches a second next action whenever the current state is an odd number.

store.subscribe(() => { 
  if (store.getState() % 2 === 1) {
    store.dispatch({
      type: 'next',
    })
  }
})

#Sources

There’s an important difference between Observables and Redux-like stores — which I’m going to start calling Sources, and which I’m going to define as having a getCurrentValue() function in place of getState().

interface Source<T> {
  subscribe(onChange: () => void): () => void
  getCurrentValue(): T
}

While an Observable passes every value to every subscribe callback, a Source makes no such guarantee; it can skip values. This makes Sources less capable than Observables in some ways; for example, you can’t reduce over a Source’s values. Interestingly though, this limitation actually makes Sources a much better fit for building UIs with React, because it allows for an interesting possibility.

What if there is no current value?

What if getCurrentValue() throws an Error? What if it throws a Promise? What if you pass a source that throws an Error or Promise to React’s useSubscription hook? You’ll get Suspense and Error Boundaries support without writing a single line of component or hook-based code.

Okay James, but what’s your point?

Let me be clear: I’m not suggesting you throw out Apollo Client and switch back to Redux — after all, Redux’s getState() can’t throw promises. But it is food for thought.

]]>
[email protected] (James K Nelson)
<![CDATA[The big 2019 Frontend Armory update]]> https:/frontarm.com/james-k-nelson/update-2019/ https:/frontarm.com/james-k-nelson/update-2019/ Sun, 24 Nov 2019 00:00:00 GMT

G’day there! It’s been about a year since my last status update, and a big year at that. I’ve released a bunch of new lessons and code, a couple new videos, a new direction for the site, and a much lower price. But before talking about any of this, let’s rewind to earlier this year.

React hooks were released.

Hooks promised to completely change the way you’d write React apps. Which at the time, sounded like a whole lot of work. It meant that you’d need to learn new patterns, new ways of thinking, and new libraries. Given this reality, it took some time before I was truly convinced about the merit of hooks — but after using them in the real world for some months, you can consider me convinced. Hooks are pretty great.

At least, hooks are great as a developer. As someone who’d just gone full time on Frontend Armory and spent months writing a course on React with class components, hooks were pretty bad timing for me. They’re a completely different beast to class components, and I needed time to get comfortable with them before I could teach them. This left Frontend Armory in a slightly different position than I expected it would be just one year back — so let’s talk about what has changed.

#New lessons and code

#React Fundamentals

When I launched Frontend Armory last year, it had just one course: React (without the buzzwords). And then like a week later, I heard the first news about React Hooks. Doh.

The thing about hooks is that they’re not just a different way of writing class components — they’re a completely different way of thinking about state and effects. Basically, I needed to rewrite a large part of the course. So in 2019, that’s what I did.

The updated course is called React Fundamentals. It now:

  • Introduces Create React App near the beginning of the course.
  • Uses JSX for most of the examples.
  • Teaches state and effects using hooks.
  • Teaches you to build a fancy pancy hooks-based fractal tree that reacts to mouse movements and clicks. Go ahead, try it below!
import React, { useEffect, useState } from 'react'
import ReactDOM from 'react-dom'
import FractalTreeBranch from './FractalTreeBranch'

// The height and width of the entire window
const { innerHeight, innerWidth } = window

const FractalTree = () => {
  let [time, setTime] = useState(() => Date.now())
  let [mousePosition, setMousePosition] = useState({
    x: innerWidth / 2,
    y: innerHeight / 2,
  })
  useEffect(() => {
    let requestId = window.requestAnimationFrame(() => {
      setTime(Date.now())
    })
    return () => {
      window.cancelAnimationFrame(requestId)
    }
  })
  let fromHorizontalCenter = (innerWidth / 2 - mousePosition.x) / innerWidth
  let fromVerticalCenter = (innerHeight / 2 - mousePosition.y) / innerHeight
  let lean = 0.03 * Math.sin(time / 2000) + fromHorizontalCenter / 4
  let sprout =
    0.3 +
    0.05 * Math.sin(time / 1300) +
    fromVerticalCenter / 5 -
    0.2 * Math.abs(0.5 - fromHorizontalCenter / 2)

  return (
    <div
      style={{
        position: 'absolute',
        top: 0,
        left: 0,
        bottom: 0,
        right: 0,
        overflow: 'hidden',
      }}
      onMouseMove={event => {
        setMousePosition({
          x: event.clientX,
          y: event.clientY,
        })
      }}>
      <FractalTreeBranch lean={lean} size={150} sprout={sprout} />
    </div>
  )
}

ReactDOM.render(<FractalTree />, document.getElementById('root'))

React fundamentals is a huge improvement on the earlier React (without the buzzwords) course. There’s just a few outstanding issues:

  • It only includes one video. I’ve recorded a few other videos this year, but ran into some issues on this front — I’ll go into more detail later in the update.
  • Some of the later lessons in React Fundamentals are works in progress in that they’re still based around the older React (without the buzzwords) course.

I plan on updating the later lessons in the coming year, but for now you’ll find more details on building practical apps in…

#React, Firebase & Bacon

In recent years, it’s become much easier to learn advanced React features — mostly due to the massibe imporvements in the React docs themselves. But at the same time, there are now more concepts and tools to learn, and more ways that the various pieces can fit together.

As a result, while React itself has become easier to learn, it’s also become less clear how to put it to use in real world apps. And that’s where React, Firebase & Bacon comes in.

This work-in-progress course aims to be a step-by-step guide to building a real world app from the ground up. So far, it includes lessons on:

  • Setting up your Create React App & Firebase project
  • Fetching and submitting data
  • Working with simple forms
  • Styling your app with styled-components, a popular CSS-in-JS library

Each of these lesson covers one step in the process towards building this landing page:

import { createBrowserHistory } from 'history'
import React, { useEffect, useState } from 'react'

import { NarrowCardLayout, StyledHaiku } from './components'
import Landing from './landing'

const history = createBrowserHistory()
const navigate = path => history.push(path)

function getRoute(location) {
  switch (normalizePathname(location.pathname)) {
    case '/':
      return <Landing navigate={navigate} />

    case '/privacy':
      return <Privacy navigate={navigate} />

    case '/thanks':
      return <Thanks navigate={navigate} />

    default:
      return <NotFound navigate={navigate} />
  }
}

export default function App() {
  const [location, setLocation] = useState(history.location)

  useEffect(() => history.listen(setLocation), [])

  return getRoute(location)
}

function NotFound({ navigate }) {
  return (
    <NarrowCardLayout navigate={navigate}>
      <StyledHaiku>
        I couldn't find it
        <br />
        The page probably hates me
        <br />
        I'm really depressed
      </StyledHaiku>
    </NarrowCardLayout>
  )
}

function Privacy({ navigate }) {
  return (
    <NarrowCardLayout navigate={navigate}>
      <StyledHaiku>
        Your privacy is
        <br />
        Very important to us
        <br />I wrote a poem
      </StyledHaiku>
    </NarrowCardLayout>
  )
}

function Thanks({ navigate }) {
  return (
    <NarrowCardLayout navigate={navigate}>
      <StyledHaiku>
        Thanks for joining in!
        <br />
        When we're ready to wow you,
        <br />
        You'll get an email.
      </StyledHaiku>
    </NarrowCardLayout>
  )
}

function normalizePathname(pathname) {
  if (pathname === '/' || pathname === '') {
    return '/'
  }

  // Add leading slash
  pathname = pathname[0] !== '/' ? '/' + pathname : pathname

  // Strip trailing slash
  pathname =
    pathname[pathname.length - 1] === '/' ? pathname.slice(0, -1) : pathname

  return pathname
}

In fact, the above landing page is open source, with separate branches for each step — including the ones that aren’t yet covered in the course.

Okay, okay but… why bacon?

Before answering this, I need to stress that this course is currently a work in progress. I’ll be releasing updates on a when-they’re-done basis — but the direction of the course is set in stone. Let me explain: once the course is complete, it’ll teach you to build a real-world app that makes bacon (money). The app you’ll be building is called Vouch, and Pro members already have access to a significant chunk of the source for the finished product.

#Vouch

Vouch is the companion app to React, Firebase & Bacon. It’s an advertising-free social network, and as with the course, it’s a work in progress — but it’s a lot further along than the course content itself. It’s source is exclusively available to Frontend Armory Pro members, including:

  • Working payments (with Stripe)
  • Server rendering (with Create Universal React App)
  • Authentication (with Firebase)
  • Onboarding flow
  • Responsive layout

The main missing feature? Posting. Yep, it’s a social network that doesn’t let you post anything. There’s a reason for this, though: I want Vouch to eventually be a real, useful, open-source app — not just a demo. And to make that happen, Vouch is going to let you post JavaScript demos using the same Demoboard component that the course’s exercises currently use. This means that Demoboard needs to be a reusable component. And as of a few weeks ago, it actually is!

#Demoboard

I’m often asked the question: why does Frontend Armory use its own Demoboard component? Why not just use CodeSandbox? It’s a great question, and honestly, there are a lot of ways I could answer it. To start with, CodeSandbox didn’t even exist when I started work on the first version of Frontend Armory. But there’s another, more important reason.

CodeSandbox is designed to let you edit real world code in the browser. It’s amazing at what it does, but Demoboard — the editor that runs the fractal and landing page examples above — does something different. It lets you quickly throw together small demos. And moreover, it lets you render a lot of those demos on a single page.

Demoboard is designed to be lightweight. It loads quickly, and loads even quicker when you have multiple demoboards on a page (as they’ll share the build worker). It’s also server-renderable, speeding up the time to initial content. It also works without a server at all — it can read everything it needs from a JavaScript CDN like UNPKG.

As of a few weeks ago, Demoboard is now open source.

Documentation is still to come, and the API is subject to change — but even in its current state, you can embed Demoboards in your site or docs with a simple yarn add @frontarm/demoboard. You can see how to do so at demoboard.io — where the open-source demoboard project will be living from here on out.

Demoboard is the engine that drives Frontend Armory, and it’ll be the engine that drives Vouch too. But why Demoboard and Vouch? And why bacon?

#The mission

Without going into the details, I grew up in a place with a rather low socioeconomic rank. Remote work on the internet was a ladder up for me — and it’s a ladder that I want to help keep open for others. But actually, when I started Frontend Armory, I hadn’t yet realized this. All I knew was that I wanted to teach.

But what should I teach? The obvious thing to teach was JavaScript and React. I know JavaScript and React. But there’s been something that’s made me increasingly uncomfortable about teaching web tech just for the sake of it: the advertising economy. I’m not a huge fan of ads. And that’s why I want to teach people to build apps without them.

My mission for Frontend Armory is to teach people the skills they need to build apps that charge money.

Each piece of new content this year has been one step towards this mission:

  • Demoboard helps teachers make quality material by simplifying the process of embedding exercises
  • Vouch will encourage learning in public
  • React, Firebase & Bacon is the roadmap to get where students are going

This mission has helped give better direction to Frontend Armory’s content over the past few months — and it’s also resulted in another important change.

#A more accessible price

Pricing is hard.

On one hand, for a service like Frontend Armory to be sustainable, it needs to cost money — because I need to be able to feed and house my family. On the other hand, if the price is too high for the people that actually need it, then I’m basically just wasting my time. The price needs to be sustainable, but it also needs to be accessible.

When I first launched Frontend Armory, the price was $40/month or $250/year. However, it soon became apparent that this put it out of reach for a lot of people who needed it most. To try and strike a better balance with accessibility, I’ve cut Frontend Armory Pro’s monthly price by more than half.

Frontend Armory Pro is now just $18/month, or $180/year.

Join Frontend Armory Pro Now »

#Business and financials

In the interest of transparency and learning in public, here’s some data from the first year of Frontend Armory:

  • Revenue for the first year was roughly USD $20,000 (2,160,000 yen)
  • There have been 170 customers in total (and as far as I know, my mum didn’t sign up to pad the numbers!)
  • Various hosting and business costs amounted to roughly USD $3,000
  • Which all adds up to a huge loss if I value my time at even half of minimum wage

Let me share a few other business-related things I’ve learned over the first year, in no particular order:

  • Curating and editing content from others is hard. It takes almost as much time as writing my own content. While I’d still like to publish other authors, I first need to learn to better market my own content.
  • Extolling the virtue of my own content is mostly a waste of time. It’s far more valuable to have others vouch for my product than to do so myself.
  • Surprisingly, organic traffic from google has increased significantly, even during periods where I haven’t been regularly blogging…
  • But organic traffic doesn’t have a great conversion rate to paying customers.
  • GitHub stars don’t pay the bills.
  • Real-life workshops do pay the bills, but…
  • Marketing and sales take a whole lot of time, which can’t be spent on creating content.

Initially, my plan was to create content for Frontend Armory full time — and for the better part of a year I managed to do so. However, it turns out I still have a lot to learn about marketing and business. With this in mind, for at least the next half year, I’m aiming to spend only 2–3 days a week on Frontend Armory. I’m treating this as a bit of a time to recharge and try new things without the stress of a limited runway.

#What else didn’t go right

If you’ve been following along since last year, you might have noticed a few things conspicuously missing from the new lessons and code.

#Videos

So far, Frontend Armory’s content has mostly been text and demo based — because in my opinion, these are usually the best mediums for building a deep understanding of a topic. But with this said, video does have its place. In particular, I’ve wanted to create video introductions for course topics, and video solutions for the more involved exercises. In fact, early on in the process of planning the React, Firebase & Bacon course, I did create a couple videos. Here’s what I learned:

  • Videos take a lot of time to get to the quality I want.
  • Unlike text, if the content changes, I can’t easily edit them; I have to start from scratch.
  • I can’t take good video with two huge construction sites next door.

In any case, I have learned a lot about video, and plan on having another go once the text for the first few parts of React, Firebase & Bacon is done — and once the construction next door finishes (or I give up waiting and move).

Towards the beginning of the year, I released a new version of my Navi router — with hooks, and a bunch of other neat features. Navi has come a long way, and is used in a number of production apps — including Frontend Armory and a number of apps by other contributors.

Recently though, the React team has been heading in a new direction, which makes me unsure of whether Navi has a future. React itself is gaining more and more responsibility, which makes it less and less certain that external state management solutions like Navi will continue to work well into the future. In particular, I’ve even seen talk of React integrating with bundlers and the server itself. Due to the uncertainty this brings and my limited time, I’ll be pausing work on new features, and continuing only with basic maintenance.

#Communication

If you’ve read this far in, then thanks for reading! And also, chances are you’re someone who might have noticed that I haven’t been hugely communicative over the past year.

There are a number of reasons for this, but let me cover a few of the big ones.

  1. The change from class components to hooks was quite hard on me. I don’t want to teach something that I haven’t had time to become confident with, which means I didn’t really have much to say for the first part of the year — I just didn’t have the experience using hooks in real world code to actually teach them.
  2. Even after gaining familiarity with hooks, I’ve hesitant to spend much effort teaching many existing patterns, due to the near-certainty that they’ll soon be obsolete. The announcement of Concurrent Mode in October has only reinforced this opinion.
  3. As a result, for the first part of the year, I wasn’t able to create much that I personally felt had enough value to broadcast to the world.

Over the past few months however, I felt like I’m gaining my feet again. Instead of teaching React itself, I’ve focused on teaching how to build apps that use React. Instead of teaching the latest React patterns and APIs, I’ve been teaching the tools that I use right now in a real app. And while I’m not going to promise you updates at any specific frequency, I will be more communicative over the coming year.

#One last silly little thing

Near the beginning of 2019, I bought a big Lego rocket, and I gave myself a rule: one page of the instruction booklet gets built for each major piece of content that goes online.

Here’s an image I posted just after I got the rocket, on January 23:

Unimplemented.

And here’s the rocket now — after building 76 pages:

Unimplemented.

As silly as it sounds, the rocket has been a great motivator for me. Each time I add another brick to the rocket, it means I’ve taken one more meaningful step towards helping people to learn skills that can build them a better life.

If you’ve already become a Frontend Armory Pro member, then you’ve helped build 76 pages of rocket towards that goal. And if not, then now’s the perfect time to join! You’ll not only get immediate access to:

  • The Vouch source code
  • All member-exclusive content
  • Early access to new content
  • The member’s lounge slack room (where I answer questions a lot more reliably than I do via Twitter or Email)

If you join in now, you’ll also be helping to move another 100 pages closer to the goal of creating Frontend Armory, Vouch and Demoboard — and helping people teach themselves a valuable skill in the process.

(Oh yeah, and since it’s late November, I’ve dropped the yearly price from $180 to $150 — it’ll stay at that price until November 31.)

So join Frontend Armory Pro now »

Thanks so much for reading! Can’t wait to see you again at the next update :-)

]]>
[email protected] (James K Nelson)
<![CDATA[A deep dive into React effects]]> https:/frontarm.com/james-k-nelson/introduction-to-react-effects/ https:/frontarm.com/james-k-nelson/introduction-to-react-effects/ Sun, 25 Aug 2019 00:00:00 GMT

Imagine that for some reason, you’ve decided to create a React component that renders an animated fractal tree. In fact, let’s say that you’re already 90% of the way there — you have a fractal tree component, and now you want to animate it.

import React, { useState } from 'react'
import FractalTreeFrame from './FractalTreeFrame'

// The height and width of the entire window
const { innerHeight, innerWidth } = window

export default function App() {
  const [mousePosition, setMousePosition] = useState({
    x: innerWidth / 2,
    y: innerHeight / 2,
  })

  return (
    <FractalTreeFrame
      mousePosition={mousePosition}
      onMouseMove={({ clientX: x, clientY: y }) =>
        setMousePosition({ x, y })
      }
      time={Date.now()}
    />
  )
}

If you move the mouse around the preview area, you’ll see that the tree is already somewhat animated, due to the onMouseMove handler:

onMouseMove={({ clientX: x, clientY: y }) =>
  setMousePosition({ x, y })
}

Each time the mouse moves over the preview area, React calls this event handler. This in turn updates the component state, triggering a re-render of the component with a new value of the time prop.

time={Date.now()}

Of course, it won’t do to require the user to constantly move their mouse to keep the animation going. Ideally, the component would automatically schedule a new frame after each frame is rendered, using something like the browser’s requestAnimationFrame() function.

As it happens, there’s a pretty obvious way to make this work. Given that updating the state also triggers a re-render, you can store the current time with a useState hook. Then, you can trigger re-render by updating the time in a requestAnimationFrame() callback. To try it out, just uncomment lines 14–17 below:

import React, { useState } from 'react'
import FractalTreeFrame from './FractalTreeFrame'

// The height and width of the entire window
const { innerHeight, innerWidth } = window

export default function App() {
  const [time, setTime] = useState(Date.now())
  const [mousePosition, setMousePosition] = useState({
    x: innerWidth / 2,
    y: innerHeight / 2,
  })

  // window.requestAnimationFrame(() => {
  //   // Update time to trigger a re-render
  //   setTime(Date.now())
  // })

  return (
    <FractalTreeFrame
      mousePosition={mousePosition}
      onMouseMove={({ clientX: x, clientY: y }) =>
        setMousePosition({ x, y })
      }
      time={time}
    />
  )
}

Once you’ve removed the comment above, this animation looks to work pretty well! That is, at least until you try moving the mouse over the tree as well. Go ahead, try quickly moving your mouse over the tree, and see how performance takes a nosedive.

What the hell is going on?

Here’s the problem: if the mouse moves, then React will update the state and re-render the component, thus scheduling another render in addition to the one already scheduled by requestAnimationFrame(). Now you have two scheduled renders, twice the CPU usage, half the frame rate, and everything starts to grind to a halt.

#So… effects?

In the above example, the call to window.requestAnimationFrame() is what’s called a side effect; it’s something that your component does in addition to returning elements.

Side effects are what make your application actually useful. They’re responsible for things like:

  • Loading data from the server
  • Setting and clearing timers
  • Interacting with the DOM

As you can see from the above example, it’s entirely possible to put effectful code directly in the component function. The thing is, the resulting effects occur each and every time the component function is called — which is rarely the desired behavior. More often, you’ll want the effect to occur in response to specific conditions — and to stop occurring once those conditions are removed.

#The useEffect() function

This hook function lets you ask React to do something after the component has finished rendering to the DOM. There are a few ways to use it, so let’s start with the simplest:

useEffect(() => {
  // do stuff after update
})

When useEffect() receives a function as its first and only argument, it’ll call that function on every update. You might use this to, for example, validate usernames in a social network’s onboarding sequence. You can see how I’ve approached this below — go ahead, try typing in a username to test it out!

import React, { useEffect, useState } from 'react'
import getUsernameAvailability from './getUsernameAvailability'

export default function App() {
  const [username, setUsername] = useState('')
  const [availability, setAvailability] = useState({})
  const handleChange = event => setUsername(event.target.value)

  useEffect(() => {
    if (username && username !== availability.username) {
      // The promises returned by getUsernameAvailability
      // will always resolve in the same order as they're created,
      // so we don't have to worry about race conditions here.
      getUsernameAvailability(username).then(
        isAvailable => setAvailability({ username, isAvailable })
      )
    }
  })

  return (
    <div className="nametag">
      <h2>Hello</h2>
      <label>
        <p>my username is</p>
        <div className="field">
          <span className="at">@</span>
          <input value={username} onChange={handleChange} />
          <span className="icon">
            {username && availability.username === username && (
              availability.isAvailable ? "✔️" : "❌"
            )}
          </span>
        </div>
      </label>
    </div>
  )
}

In the above example, the effect starts by checking whether validation still needs to be performed for the current username. Then, if validation is still required, it calls getUsernameAvailability() and saves the result to component state.

While it may seem like a minor (and imperfect) optimization, the if statement inside the above effect is actually incredibly important. Do you know why?

Spoiler

Without the if statement, you get an infinite loop.

Saving the validation result to component state triggers another update, which triggers the effect, which triggers the update, which… yeah, you get the idea.

Effects often need to update component state, and this presents a bit of a problem: if you run these effects in response to every update, you can easily end up with infinite loops. Typically though, you don’t want to run effects in response to every update. You only want them to respond to specific events — and that’s where the second argument of useEffect() comes in.

#Conditional effects

The second argument to useEffect() — called the dependencies array — instructs React to only run the effect if a dependency has changed from its previous value.

useEffect(
  () => {
    // do stuff after specified updates
  },
  [executeWhenThisChanges, orWhenThisChanges]
)

The dependencies array gives you a simple way to create effects that respond to specific events, without running into infinite loops. And with that in mind, let’s revisit the username example with an exercise.

Your task is to refactor the below example with a dependencies array, so that it no longer uses an if statement.

Be careful to add the dependencies array before removing the if statement though — otherwise you’ll end up with an infinite loop!

import React, { useEffect, useState } from 'react'
import getUsernameAvailability from './getUsernameAvailability'

export default function App() {
  const [username, setUsername] = useState('')
  const [availability, setAvailability] = useState({})
  const handleChange = event => setUsername(event.target.value)

  useEffect(() => {
    if (username && username !== availability.username) {
      // The promises returned by getUsernameAvailability
      // will always resolve in the same order as they're created,
      // so we don't have to worry about race conditions here.
      getUsernameAvailability(username).then(
        isAvailable => setAvailability({ username, isAvailable })
      )
    }
  })

  return (
    <div className="nametag">
      <h2>Hello</h2>
      <label>
        <p>my username is</p>
        <div className="field">
          <span className="at">@</span>
          <input value={username} onChange={handleChange} />
          <span className="icon">
            {username && availability.username === username && (
              availability.isAvailable ? "✔️" : "❌"
            )}
          </span>
        </div>
      </label>
    </div>
  )
}

Did you have a go? Great! In that case, if you take a look at the solution for the above exercise, you might notice something interesting. Here’s the original:

useEffect(() => {
  if (username !== availability.username) {
    // ...
  }
})

In contrast, here’s the solution with a dependencies array:

useEffect(() => {
  if (username) {
    // ...
  }
}, [username])

At first, there might not seem to really be any point in making this change. Sure, it saved you a couple characters… but if you look a little closer, there’s something far more exciting going on. Do you know what it is? Have a little think about this before checking the box below.

Spoiler

Actually, there are two exciting things going on here!

First, there’s the fact that the number of validations is cut in half — you can confirm this by opening up the console in both of the above examples. This is because the effect is now only being run when the username has changed — as opposed to running when it differs to the last received username. It gives you a better result, despite using less code. Which brings me to the second exciting thing.

While the condition in the first snippet references two variables: username, and availability.username, the second snippet only needs the username. By using the dependencies array, you’ve eliminated the need for an extra piece of state!

The key feature of useEffect() is that it lets you specify not just what effect to run, but also when that effect should occur — and it lets you do this declaratively, without relying on component state at all! In fact, it actually takes this one step further: it lets you declare how the effect should end.

#The cleanup function

When you return a function from your useEffect() callback, React will call that function when the effect should no longer have any… effect. lol, sorry not sorry.

useEffect(
  () => {
    // do stuff after specified updates

    return () => {
      // finish doing stuff
    }
  },
  [executeWhenThisChanges, orWhenThisChanges]
)

This function is often called the cleanup function, and there are two situations in which React will call it. Do you know what they are? Have a think about it, and when you’re ready, check your answer below.

Spoiler

The cleanup function will be called:

  1. When the component is unmounted
  2. On the next time that the effect callback is run

The first of these situations is hopefully fairly obvious. But what about the second situation? This is what makes the effect hook so powerful. It lets you declare to React:

Yo React, I want this thing to happen, but only until the next time it happens (or until it no longer can happen).

The cleanup function is particularly important when dealing with data subscriptions — I’ll cover more on this in the routing section of React, Firebase & Bacon. For the moment though, let’s jump back to where we started: the animated tree.

In order to smooth out the tree’s animation, all you need to do is finish off the effect in the demo below. The thing is, there are actually two approaches that you can take. Do you know what they are? If so, try them out in the editor — and then check below to find out which one works best.

import React, { useEffect, useState } from 'react'
import FractalTreeFrame from './FractalTreeFrame'

// The height and width of the entire window
const { innerHeight, innerWidth } = window

export default function App() {
  const [time, setTime] = useState(Date.now())
  const [mousePosition, setMousePosition] = useState({
    x: innerWidth / 2,
    y: innerHeight / 2,
  })

  // useEffect(() => {
  //   window.requestAnimationFrame(() => {
  //     // Update time to trigger a re-render
  //     setTime(Date.now())
  //   })
  // })

  return (
    <FractalTreeFrame
      mousePosition={mousePosition}
      onMouseMove={({ clientX: x, clientY: y }) =>
        setMousePosition({ x, y })
      }
      time={time}
    />
  )
}

Did you find both approaches?

Spoiler
#Approach 1: conditional effects

Given that time is only updated within requestAnimationFrame, you can limit the number of renders by adding time as a dependency.

useEffect(() => {
  window.requestAnimationFrame(() => {
    setTime(Date.now())
  })
}, [time])

So long as the tree is the top level component, this approach works fine and dandy. Be careful, though — if this component is not at the top level and is then unmounted inside a running application, it would cause a warning, as setTime would still be called after unmount.

#Approach 2: cleanup function

By calling cancelAnimationFrame in the cleanup function, you’ll ensure that any scheduled updates are cancelled when you move the mouse.

useEffect(() => {
  const frame = window.requestAnimationFrame(() => {
    setTime(Date.now())
  })
  return () => {
    window.cancelAnimationFrame(frame)
  }
})

I’d recommend taking this approach, for two reasons:

  1. It’ll work just as well if you decide to update time elsewhere
  2. It’ll work just as well if the component is mounted elsewhere

#The three rules

Phew, that was a lot of info on effects! It’s okay if you didn’t take it all in — as you keep using effects in your day-to-day (or in my React, Firebase & Bacon course), you’ll gradually build intuition for them. But to start with? All you need to remember is these three rules:

  1. useEffect() schedules an update after the DOM has been updated
  2. By passing a dependencies array, that update will only occur if a dependency has changed
  3. If you return a cleanup function, it’ll be called when the effect should should no longer apply

Got these three rules down? Good. Let’s see if we can’t put 'em all into practice with an exercise.

#Exercise: debounce the username form

If you take a look at the console for this example, you’ll see that as you type, a separate validation request is made for each and every keystroke. Given that at some level you’re going to be charged per request… well, if your app grows large enough, a little debounce could save a lot of bacon.

But what do I mean by debouncing? Simple: instead of validating each and every keystroke, you’ll want to delay validation until the user has stopped typing for a short period. Roughly speaking, here’s how to achieve this:

  1. When the user updates the input, you’ll use setTimeout() to schedule a validation to occur a few hundred milliseconds in the future.
  2. If the user updates the input again before the previously scheduled validation has occurred, then cancel it with clearTimeout() before scheduling another one.

Your task is to debounce the username input so that validation runs no more than once every 500ms.

You can check your work by opening up the console, and watching how many requests are made as you type. Then, once you’re happy with your work (or if you’re stuck but you’ve given the exercise a solid try), compare your work with my solution by clicking the solution button at the bottom left.

import React, { useEffect, useState } from 'react'
import getUsernameAvailability from './getUsernameAvailability'

export default function App() {
  const [username, setUsername] = useState('')
  const [availability, setAvailability] = useState({})

  useEffect(() => {
    if (username) {
      getUsernameAvailability(username).then(
        isAvailable => setAvailability({ username, isAvailable })
      )
    }
  }, [username])

  return (
    <div className="nametag">
      <h2>Hello</h2>
      <label>
        <p>my username is</p>
        <div className="field">
          <span className="at">@</span>
          <input
            value={username}
            onChange={event => setUsername(event.target.value)}
          />
          <span className="icon">
            {username && availability.username === username && (
              availability.isAvailable ? "✔️" : "❌"
            )}
          </span>
        </div>
      </label>
    </div>
  )
}

This article is based on the useEffect() lesson in React, Firebase & Bacon. If you found this lesson useful, then there’s plenty more demos, exercises and in-depth explanations where it came from. Check it out — I think you’ll love it! 🤓

]]>
[email protected] (James K Nelson)
<![CDATA[When to Use Custom React Hooks]]> https:/frontarm.com/james-k-nelson/react-hooks-intuition/ https:/frontarm.com/james-k-nelson/react-hooks-intuition/ Wed, 06 Mar 2019 00:00:00 GMT

It’s been almost a month since React Hooks were released, and they already seem to be taking over the world — thanks in no small part to the power of custom hooks.

Custom hooks do for state and side effects what React components did for views; they make it insanely easy to share and reuse small pieces of code. As a result, all sorts of packages now export custom hooks — my own package included. But there’s a catch.

Let’s investigate the catch by diving into an example, before building some intuition around when to use custom hooks — and when to use something else.

#Have you ever used an app with no lists?

Imagine that you’re building an app with a contact form. To start out, you may decide to store the form’s state within the Form component itself, using the useState() hook.

let [name, setName] = useState(defaultValue.name || '')
let [email, setEmail] = useState(defaultValue.email || '')

To ensure reusability, you put this state management code into a useContactModel() custom hook, that can be used whenever a contact form is required within your app.

function useContactModel({ defaultValue }) {
  let [name, setName] = useState(defaultValue.name || '')
  let [email, setEmail] = useState(defaultValue.email || '')

  return {
    error: name === '' ? 'Please enter a name' : undefined,

    // Contains objects that can be spread onto <input> elements
    inputProps: {
      name: {
        value: name,
        onChange: e => setName(e.target.value),
      },
      email: {
        value: email,
        onChange: e => setEmail(e.target.value),
      },
    }
  }
}

Simple, huh? Hooks make this kind of thing super-duper easy. But what if the customer then asks you why you only allow for entry of a single contact, as opposed to a list of contacts? No worries, Contact is a component. Turning it into a list is as simple as creating a ContactList component and rendering Contact a few times.

import React from 'react'
import { useContactModel, useKeys } from './hooks'

export function Contact({ onRemove }) {
  let model = useContactModel()

  return (
    <div>
      <label>Name: <input {...model.inputProps.name} /></label>
      <label>Email: <input {...model.inputProps.email} /></label>
      <button onClick={onRemove}>Remove</button>
      {model.error && <p>{model.error}</p>}
    </div>
  )
}

export function ContactList() {
  let [keys, add, remove] = useKeys(3)

  return (
    <>
      {keys.map(key =>
        <Contact key={key} onRemove={() => remove(key)} />
      )}
      <button onClick={add}>Add</button>
    </>
  )
}

So far, so good. There’s just one problem: you need to be able to save the contacts. And given that your API requires that you send the entire list at once, you’re going to need to have access to an array containing all that data.

If the state is all stored in child components, then you can’t just access the data from the parent. But no problem — useContactModel() is a hook, so you can just lift the whole thing into the parent component, right?

import React from 'react'
import { useContactModel, useKeys } from './hooks'

export function Contact({ model, onRemove }) {
  return (
    <div>
      <label>Name: <input {...model.inputProps.name} /></label>
      <label>Email: <input {...model.inputProps.email} /></label>
      <button onClick={onRemove}>Remove</button>
      {model.error && <p>{model.error}</p>}
    </div>
  )
}

export function ContactList() {
  let [keys, add, remove] = useKeys(3)
  let contactModels = keys.map(useContactModel)

  return (
    <>
      {keys.map((key, i) =>
        <Contact
          key={key}
          model={contactModels[i]}
          onRemove={() => remove(key)}
        />
      )}
      <button onClick={add}>Add</button>
    </>
  )
}

Waaait a minute… in the above example, useContactModel() is called from a loop. You can’t see the loop, because it’s happening inside of the call to map(). But I can assure you that there are looping shenanigans taking place.

Now as you know, hooks aren’t like normal functions. You can’t use them just anywhere in your code. The above code shouldn’t work, and indeed it doesn’t — just try adding or removing a contact…

#Hooks can’t (always) be lifted up

At times, you can think of custom hooks as components for state management. But this mental model breaks down after a point: while components can be rendered within loops and conditions, hooks can’t. And this has an important side effect:

Custom hooks can’t be lifted out of components that are rendered inside of conditions or loops.

Hooks aren’t like reducers; you can’t just compose them together into one big hook that holds the entire application’s state. Instead, you’ll need to call any useState() hooks closer to where the state is actually rendered — and this is by design:

Unimplemented.

While hooks do let you reuse stateful and effectful code across components, they still force you to associate that code with a component — and its associated position in the DOM. As a result, hooks come with many of the same constraints as class components:

  • What if you need to call a hook within a loop?

    Then you’ll need to put the hook in a child component and call it there.

  • What if you then want to access the result of those hooks in the parent component?

    Then you’ll need to lift the state back up into the parent component and refactor to avoid calling hooks in loops — e.g. by replacing multiple useState() hooks with a single useReducer().

  • What if you then want that state to stick around after the component is unmounted?

    Then you’ll need to lift the state up even further — and probably refactor again.

As you can see, custom hooks aren’t really “components for state and side effects” — they’re too dependent on their context to be thought of as components. But if they’re not components, then what are they?

#Hooks are mixins

Once upon a time, React had a feature called mixins that let you reuse small groups of lifecycle methods and state across multiple components. React’s mixins had a number of issues which caused them to be deprecated, but the need for a way to share functionality between components is as a strong as ever. And that’s what hooks are: a way to share stateful and side-effectful functionality between components.

Ryan Florence actually made this connection before hooks were even announced. But personally speaking, it wasn’t until I started running into the limitations of hooks that the connection really struck.

Ok, so hooks are mixins. It’s a fun connection to make — but does this mean anything in practice? Actually, I’ve found this to be a good way to intuitively understand whether something can should be done with hooks:

  • Should I try and create a Redux-like store that holds my entire app’s state by mixing things into a component? No? Then it doesn’t make sense with hooks either.

  • Should I try to create models that store state for a large form by mixing things into a component? No? Then hooks probably aren’t a great way to do this either.

  • Would mixins be an appropriate way to make a component subscribe to a global store? Yes? Then hooks will work for that too!

And we’re not done yet. There’s one more thing that hooks-are-mixins means in practice, and it’s a biggie…

#Don’t throw out your state manager.

While hooks are a great way to reuse stateful code across components, they’re still tied to components. Sometimes you’ll need state that isn’t tied to a component — things like:

  • A cache of data that has been received from the server (e.g. Apollo)
  • The status of any drag-and-drop interactions (e.g. react-dnd)
  • The current user’s authentication state (e.g. using Firebase or Auth0)
  • Any async data that depends on the current URL (e.g. using Navi)

While hooks are local, some state is global. And that means that state managers will always be your friend! With that said, hooks and state managers aren’t mutually exclusive.

In order to render any global state, you’ll first need to subscribe to it and store it in component state — and hooks are a great way to do this. For an example of how to do this, check out Daishi Kato’s recent guide to creating hooks to subscribe to a Redux store (with Proxies).

So here’s the thing: hooks are an incredible tool. I feel like they’re the missing piece that React has needed since Mixins were deprecated. But like any tool, hooks don’t suit every situation, and the key to getting the most out of them is to understand when to use them — and when to use something else.

Thanks for reading all the way to the end! If you liked this article and want to read more like it, then now’s a great time to join Frontend Armory’s weekly newsletter. It’s free to join — just click → here ←.

#More Reading

]]>
[email protected] (James K Nelson)
<![CDATA[useRef() and Concurrent Mode: how to avoid shooting yourself in the foot]]> https:/frontarm.com/daishi-kato/use-ref-in-concurrent-mode/ https:/frontarm.com/daishi-kato/use-ref-in-concurrent-mode/ Tue, 05 Mar 2019 00:00:00 GMT

According to the React 16 Roadmap, Concurrent Mode is just over the horizon. Expected to arrive in Q2 2019, here’s what Dan Abramov has to say about Concurrent Mode:

Concurrent Mode lets React apps be more responsive by rendering component trees without blocking the main thread. It is opt-in and allows React to interrupt a long-running render (for example, rendering a new feed story) to handle a high-priority event (for example, text input or hover). Concurrent Mode also improves the user experience of Suspense by skipping unnecessary loading states on fast connections.

While Concurrent Mode is an opt-in feature, enabling it will be simple: just wrap part of your app with a <ConcurrentMode> element:

<ConcurrentMode>
  <Something />
</ConcurrentMode>

But be aware: if your app uses useRef() the wrong way, then Concurrent Mode won’t work correctly. In fact, your entire app won’t work correctly. So to help you prepare, this short article compares some bad code with a good version, and then discusses what you can do to prepare right now.

#The bad code

Your render function should be side-effect free.

So it has always been the case that your rendering your component shouldn’t have any side effects, but it hadn’t really been an issue until Concurrent Mode appeared on the scene. In Concurrent Mode, render functions can be invoked multiple times without actually committing (meaning, for example, applying changes to the DOM).

For example, here’s a simple counter that uses useRef().

import React, { useRef } from "react";

const BadCounter = () => {
  const count = useRef(0);
  count.current += 1;
  return <div>count:{count.current}</div>;
};

export default BadCounter;

The above example works as expected in traditional React where the render phase and the commit phase is one-to-one. However, if React invokes the render function multiple time without committing, the counter will increase unexpectedly.

#The good code


import React, { useEffect, useRef } from "react";

const GoodCounter = () => {
  const count = useRef(0);
  let currentCount = count.current;
  useEffect(() => {
    count.current = currentCount;
  });
  currentCount += 1;
  return <div>count:{currentCount}</div>;
};

export default GoodCounter;

This version uses useEffect(), whose argument function is only invoked in the commit phase. currentCount is a local variable within the render function scope, so it will only change the ref count in the commit phase. The ref is essentially a global variable outside the function scope, hence modifying it is a side effect.

#The demo

import React, { useRef } from "react";

const BadCounter = () => {
  const count = useRef(0);
  count.current += 1;
  return <div>count:{count.current}</div>;
};

export default BadCounter;

#Preparing for the future

The thing about the bad counter in the above example is that it works, until you put it into a <ConcurrentMode>. So how do you know if your code is good?

This is where React’s <StrictMode> component comes in. Strict Mode intentionally invokes render functions twice, letting you find incorrect behavior during development. And <StrictMode> is available right now. For more details, see to the docs.

Finally, let me tell you a little about why I wrote this article in the first place. The reason that I’m using useRef() is to develop a bindings library for Redux, called react-hooks-easy-redux. The library must subscribe to the global store, and update the component state whenever the store’s state is updated. Refs are used to keep track of the last rendered state — I’ve made sure that they work with <ConcurrentMode>, and I’d like to share what I learned while doing so.

]]>
<![CDATA[Creating a react-redux alternative with Hooks and Proxies]]> https:/frontarm.com/daishi-kato/redux-custom-hooks/ https:/frontarm.com/daishi-kato/redux-custom-hooks/ Mon, 25 Feb 2019 00:00:00 GMT

Ever since I first learned Redux, I’ve been thinking about alternative ways to integrate it with React. My intuition was that Redux is super simple (which I like a lot), whereas react-redux’s performance optimizations make it complex. And while I’d still recommend that you use the official react-redux library for business products, if you’re playing with a toy app or you’re just starting to learn Redux, then you might want something more straightforward.

The React team recently introduced the new Hooks API, allowing for the use of stateful logic in function components. In particular, this allows for custom hooks — reusable chunks of state management logic. As a result, there have been many discussions about how to create hooks-based React bindings for Redux, and many proposals that would replace Redux completely, including mine.

But today, I’ll discuss something simpler: instead of replacing Redux, I’ll demonstrate how to develop custom hooks for Redux in a straightforward way. I’ll first describe a naive implementation, and later introduce a Proxy-based approach that seamlessly improves performance.

#A naive implementation

Let’s start with a naive implementation. If you are not familiar with the Context and Hooks APIs, please visit the official docs to learn them first. The rest of this article assumes a basic understanding of them.

First, let’s create a single context that can pass around a Redux store.

const ReduxStoreContext = React.createContext();

const ReduxProvider = ({ store, children }) => (
  <ReduxStoreContext.Provider value={store}>
    {children}
  </ReduxStoreContext.Provider>
);

We then define two hooks: useReduxDispatch() and useReduxState(). The reason we have two separate hooks is that not all components will use both hooks at the same time, and we want to hide the usage of context within the implementation.

Incidentally, the implementation of useReduxDispatch() is very simple.

const useReduxDispatch = () => {
  const store = useContext(ReduxStoreContext);
  return store.dispatch;
};

The naive implementation of useReduxState() is a little more complex, and uses four hooks: useContext(), useRef(), useEffect() and useForceUpdate().

const useReduxState = () => { 
  const forceUpdate = useForceUpdate();
  const store = useContext(ReduxStoreContext);
  const state = useRef(store.getState());
  useEffect(() => {
    const callback = () => {
      state.current = store.getState();
      forceUpdate();
    };
    const unsubscribe = store.subscribe(callback);
    return unsubscribe;
  }, []);
  return state.current;
};

Basically, we just subscribe to any changes in the Redux store’s state. (A minor note: this doesn’t support changing the store on the fly, which may be important for testing.)

We can then implement useForceUpdate() as below.

const forcedReducer = state => !state;
const useForceUpdate = () => useReducer(forcedReducer, false)[1];

#A usage example

So how would you use useReduxState(), useReduxDispatch() and <ReduxProvider>? Take a look at this simple example to find out.

import React, { useCallback } from 'react';
import store from './store';
import { ReduxProvider, useReduxState, useReduxDispatch } from './redux-bindings';

const App = () => (
  <ReduxProvider store={store}>
    <Counter />
    <TextBox />
  </ReduxProvider>
);

const Counter = () => {
  const state = useReduxState();
  const dispatch = useReduxDispatch();
  const inc = useCallback(() => dispatch({ type: 'inc' }), []);
  return (
    <div>
      <div>Count: {state.count}</div>
      <button onClick={inc}>+1</button>
    </div>
  );
};

const TextBox = () => {
  const state = useReduxState();
  const dispatch = useReduxDispatch();
  const setText = useCallback(event => dispatch({
    type: 'setText',
    text: event.target.value,
  }), []);
  return (
    <div>
      <div>Text: {state.text}</div>
      <input value={state.text} onChange={setText} />
    </div>
  );
};

export default App;

If you are familiar with Redux and react-redux, then you’ll probably notice some issues with the above example.

To start with, if you click the +1 button, not only does it re-render the Counter component — it also re-renders the TextBox component. Well, this is not a problem until it is a problem. For small apps, it works just fine. But for larger apps, it may cause problems with performance.

Really, we’d like to avoid unnecessary rendering if possible. If you were using react-redux, you might supply connect() with a mapStateToProps function to achieve this:

mapStateToProps: (state, ownProps?) => Object

mapStateToProps allows you to specify which part of the state will be used by a component. But actually defining it is a lot of extra work, and can be troublesome in some cases. It’s easy to add heavy computations in such functions, and I’ve found that beginners have trouble optimizing this due to lack of familiarity with memoization.

But what if you don’t need to specify a mapStateToProps function? What if you can use Proxy instead?

#Improving useReduxState() with Proxy

JavaScript’s new Proxy object makes it possible to automatically detect which part of the state is used during rendering. Then when your component is notified of a new state, it will know if the relevant part has changed, and can re-render only when necessary.

Let’s modify our useReduxState() hook to implement this feature. For now, we’ll only worry about the first level of the state object (and we’ll ignore state that is deep in the object tree).

const useReduxState = () => { 
  const forceUpdate = useForceUpdate();
  const store = useContext(ReduxStoreContext);
  const state = useRef(store.getState());
  const used = useRef({});
  const handler = useMemo(() => ({
    get: (target, name) => {
      used.current[name] = true;
      return target[name];
    },
  }), []);
  useEffect(() => {
    const callback = () => {
      const nextState = store.getState();
      const changed = Object.keys(used.current)
        .find(key => state.current[key] !== nextState[key]);
      if (changed) {
        state.current = nextState;
        forceUpdate();
      }
    };
    const unsubscribe = store.subscribe(callback);
    return unsubscribe;
  }, []);
  return new Proxy(state.current, handler);
};

Now, the TextBox will not be re-rendered when you click +1, and vice versa.

This implementation is somewhat limited, and you might think that the shallow comparison is not enough. Indeed, if you already have a concrete design for your state structure, then that may be the case. However, if you start designing a new state structure, you could design it with first-level separation in mind. Also, note that for complex structures where you would need reselect with react-redux, you could use useMemo() in a function component so that it returns a memoized element.

#The library

As it happens, I’ve developed a library called react-hooks-easy-redux that takes this approach. This library actually allows deep comparison thanks to proxyequal. (Still, the shallow comparison described in the previous section may work better in some use cases.)

View react-hooks-easy-redux at GitHub »

The repository contains several examples — here’s one that you can play with as a live Demoboard:

import * as React from 'react'
import { useReduxDispatch, useReduxState } from 'react-hooks-easy-redux'
import { Action, State } from './state'

const Counter = () => {
  const state = useReduxState();
  const dispatch = useReduxDispatch();
  return (
    <div>
      {Math.random()}
      <div>
        <span>Count: {state.counter}</span>
        <button type="button" onClick={() => dispatch({ type: 'increment' })}>+1</button>
        <button type="button" onClick={() => dispatch({ type: 'decrement' })}>-1</button>
      </div>
    </div>
  );
};

export default Counter;

#Final notes

There could be some edge cases where this approach or the library doesn’t work well. I would love to hear your feedback either by Twitter, or GitHub issues.

The official react-redux also has a discussion about the Proxy approach. The possibility remains open that they might implement it in the future. Would be nice.

]]>
<![CDATA[From React Hooks to... Render Props?]]> https:/frontarm.com/james-k-nelson/hooks-vs-render-props/ https:/frontarm.com/james-k-nelson/hooks-vs-render-props/ Fri, 22 Feb 2019 00:00:00 GMT

If you’ve been following the news about React lately, then you’ve probably heard about hooks. There’s been a lot of excitement about what you can build with them, and rightly so. Just take a look at all the interesting recipes on Gabe Ragland’s list.

So hooks are great. But what if I told you that everything on that list can be built without hooks? Would it still be worth learning them?

#Hooks are like Render Props

If you’ve played with hooks, then you’ve probably discovered that they’re great for consuming context. To do so, you just use the useContext() hook:

let IsStatic = React.createContext()

function HideDuringStaticRendering({ children }) {
  let isStatic = React.useContext(IsStatic)  return isStatic ? null : children
}

Of course, it’s also possible to consume context using render props:

function HideDuringStaticRendering({ children }) {
  return (
    <IsStatic.Consumer>      {isStatic => isStatic ? null : children}    </IsStatic.Consumer>  )
}

As it happens, it’s actually possible to implement almost any hook as a component that takes a render prop. But is the converse true? Can hooks replace render props?

Have a little think about this, then click below to see my answer.

Spoiler

Hooks can replace some render props, but not all of them.

Hooks can’t render anything, they can’t set values on context (even though they can consume values), and they can’t implement error boundaries. Given these limitations, you may still find yourself using render props from time to time.

#Why Hooks?

If render props are more flexible than hooks, and have been around for all this time, then why are people so suddenly excited about hooks?

To answer this, let’s do something a little odd, and reimplement a hooks-based demo with render props.

Here’s the demo. It’s pretty simple; it just renders some randomly updating data, and performs a row highlight animation after each update — using hooks.

import React, { useEffect } from 'react'
import { useData, useDidChange, useLastValue, useTimedToggle } from './hooks'
import { StyledTableRow } from './styled'

function TableRow({ id }) {
  let data = useData(id)
  let last = useLastValue(data)
  let didChange = useDidChange(data)
  let [isHighlighted, highlight] = useTimedToggle(500)

  useEffect(() => {
    if (didChange) {
      highlight()
    }
  })
  
  let change = last && (last.price > data.price ? 'down' : 'up')
  
  return (
    <StyledTableRow
      data={data}
      change={isHighlighted && change}
    />
  )
}

export default TableRow

So how would you implement this demo without hooks? To start, you could reimplement the useData and useTimedToggle hooks as components that accept a render prop, passing their values out as children — just as React’s context consumer component works.

function TableRow({ id }) {
  return (
    <Data id={id} children={data =>
      <TimedToggle
        milliseconds={500}
        children={([isHighlighted, highlight]) =>
          "..."
        }
      />
    } />
  )
}

As for the useDidChange(), useLastValue() and useEffect(), how would you implement those? Why not give it a try yourself as an exercise!

Your task is to complete the row highlight animation using render props, so that the below example behaves identically to the above example.

I’ve provided you with Data and TimedToggle components, you just need to finish off the highlight-on-change functionality. If you get stuck, you can check your answer by clicking on the “solution” button at the bottom of the editor. But please do make sure to give it a go before continuing!

import React from 'react'
import { Data, TimedToggle } from './controllers'
import { StyledTableRow } from './styled'

function TableRow({ id }) {
  return (
    <Data id={id} children={data =>
      <TimedToggle
        milliseconds={500}
        children={([isHighlighted, highlight]) =>
          <StyledTableRow isHighlighted={isHighlighted} data={data} />
        }
      />
    } />
  )
}

export default TableRow

How’d you go?

Depending on your experience with React, this exercise may be quite easy, or may feel impossible. In fact, there are a couple ways that you could answer it. But whatever approach you take, it’s going to be a pain-in-the-arse.

The problem with the above exercise is that you need to react to changes to a value passed via render prop.

In non-hooks React, reacting to changes is usually accomplished by use of the componentDidUpdate() lifecycle method. But componentDidUpdate() only knows about props and state. It doesn’t know about any values received via render prop. And so typically, if you need to watch a render function’s arguments, you’d pass them to a nested component and watch them there.

function TableRow({ id }) {
  return (
    <Data id={id} children={data =>
      <TimedToggle
        milliseconds={500}
        children={([isHighlighted, highlight]) =>
          <InnerTableRow
            data={data}            highlight={highlight}
            isHighlighted={isHighlighted}
          />
        }
      />
    } />
  )
}

class InnerTableRow extends React.Component {
  state = {
    lastChange: null,
  }

  render() {
    return (
      <StyledTableRow
        data={this.props.data}
        change={this.props.isHighlighted && this.state.lastChange}
      />
    )
  }

  componentDidUpdate(prevProps) {
    if (prevProps.data && prevProps.data !== this.props.data) {      this.props.highlight()
      this.setState({
        lastChange:
          prevProps.data.price > this.props.data.price
            ? 'down'
            : 'up'
      })
    }
  }
}

Creating a separate component works, but it is a verifiable pain-in-the-arse. Hooks solve all that.

If I was to make a terrible analogy, I’d tell you that the transition from render props to hooks feels a lot like the transition from callbacks to promises. It lets you accomplish the same thing, but you can put more in a single function. Hooks flatten things out.

So here’s the thing. React components are composable — with or without hooks. But with hooks, composing state and reactions to that state becomes far, far simpler. And that’s why you’re probably going to be using a darn lot of hooks in the not too distant future (if you’re not already, that is!)

If you need to learn more about hooks? Check out the React Hooks documentation. It’s first class. Or if you’d prefer to learn with live examples and exercises like the ones above, then you may want to join my weekly newsletter to receive more articles like this — just login with GitHub or e-mail to do so.

That’s it for me today. If you have any questions or comments, let me know on twitter at @james_k_nelson or via email at [email protected]. But until next time, happy coding!

]]>
[email protected] (James K Nelson)
<![CDATA[A React Router with Hooks and Suspense]]> https:/frontarm.com/james-k-nelson/navi-react-router-hooks-suspense/ https:/frontarm.com/james-k-nelson/navi-react-router-hooks-suspense/ Mon, 18 Feb 2019 00:00:00 GMT

So the React team just released a new API called Hooks. It’s amazing. It lets you declaratively model state and side effects. You’ve probably read about it elsewhere on the internet, so I’m not going to tell you about hooks themselves, but…

With a new API comes new possibilities. And to cut to the chase, Navi’s new <Router> component uses Hooks and Suspense to make routing simpler than ever before. It makes all sorts of things possible — you can even add animated loading transitions in just 3 lines of code.

So how do you use these new superpowered hooks? We’ll get to that in a moment. But before we do, what the hell is a <Router>?

#How many routes could a
<Router routes /> route…

It can route as many as you’d like, because Navi lets you dynamically import() entire routing trees on demand. But how?

The trick is in Navi’s method for declaring routes. For simple routes, you can just use Navi’s mount() and route() functions. But for heavier content, you can declare dependencies on asynchronous data and views using async/await — or you can even split out entire routing trees using lazy().

<Router routes={
  mount({    '/': route({      title: 'My Shop',
      getData: () => api.fetchProducts(),
      view: <Landing />,
    }),
    '/products': lazy(() => import('./productsRoutes')),  })
} />

If you take a look at this example, you’ll see that you’ve got yourself a <Router> with a couple routes, including a shop’s landing page and a lazily loadable /products URL.

Let’s build the rest of the shop.

For your next step, you’ll need to decide where to render the current route’s view element. And to do that, you just plonk down a <View /> element somewhere inside your <Router>.

ReactDOM.render(
  <Router routes={routes}>
    <Layout>
      <View />    </Layout>
  </Router>,
  document.getElementById('root')
)

Simple, huh? But waaait a minute… what if you view the lazily loadable /products URL? Then the route will be loaded via an import(), which returns a Promise, and so at first there’ll be nothing to render. Luckily, React’s new <Suspense> feature lets you declaratively wait for promises to resolve. So just wrap your <View> in a <Suspense> tag, and you’re off and racing!

import { mount, route, lazy } from 'navi'
import React, { Suspense } from 'react'
import ReactDOM from 'react-dom'
import { Router, View } from 'react-navi'
import api from './api'
import Landing from './Landing'
import Layout from './Layout'

const routes =
  mount({
    '/': route({
      title: "Hats 'n' Flamethrowers 'r' Us",
      getData: () => api.fetchProducts(),
      view: <Landing />,
    }),
    '/product': lazy(() => import('./product')),
  })

ReactDOM.render(
  <Router routes={routes}>
    <Layout>
      <Suspense fallback={null}>
        <View />
      </Suspense>
    </Layout>
  </Router>,
  document.getElementById('root')
)

#Bro, just give me the hooks?

Ok, so you’ve seen how to render a route’s view. But did you notice that your route also defines a getData() function?

route({
  title: 'My Shop',
  getData: () => api.fetch('/products'),
  view: <Landing />,
})

How do you access the data? With React hooks!

Navi’s useCurrentRoute() hook can be called from any function component that is rendered within the <Router> tag. It returns a Route object that contains everything that Navi knows about the current URL.

import React from 'react'
import { Link, useCurrentRoute } from 'react-navi'

export default function Landing() {
  // useCurrentRoute returns the lastest loaded Route object
  let route = useCurrentRoute()
  let data = route.data
  let productIds = Object.keys(data)

  console.log('views', route.views)
  console.log('url', route.url)
  console.log('data', route.data)
  console.log('status', route.status)
  
  return (
    <ul>
      {productIds.map(id => 
        <li key={id}>
          <Link href={`/product/${id}`}>{data[id].title}</Link>
        </li>
      )}
    </ul>
  )
}

Ok. So far, so good. But imagine that you’ve just clicked a link to /products — which is dynamically imported. It’s going to take some time to fetch the route, so what are you going to display in the meantime?

#Visualizing loading routes

When routes take a long time to load, you’ll want to display some sort of loading indicator to the user — and there a number of approaches that you could take. One option would be to show a fallback with <Suspense>, just as with the initial load. But this looks a bit shit.

terrible looking loading

What you’d really like to do is to display a loading bar over the current page while the next route loads… well, unless the transition only takes 100ms. Then you probably just want to keep displaying the current page until the next one is ready, because showing a loading bar for only 100ms also looks a bit shit.

loading indicator with no delay

There’s just one problem. Doing this with currently available tools is ridiculously hard, right? Well actually… You can add it to the above demo in just 3 lines of code, using the useLoadingRoute() hook and the react-busy-indicator package.

import BusyIndicator from '[email protected]'
import React from 'react'
import { Link, useLoadingRoute } from 'react-navi'

export default function Layout({ children }) {
  // If there is a route that hasn't finished loading, it can be
  // retrieved with `useLoadingRoute()`.
  let loadingRoute = useLoadingRoute()

  return (
    <div className="Layout">
      {/* This component shows a loading indicator after a delay */}
      <BusyIndicator isBusy={!!loadingRoute} delayMs={200} />
      <header className="Layout-header">
        <h1 className="Layout-title">
        <Link href='/' prefetch={null}>
          Hats 'n' Flamethrowers 'r' Us
        </Link>
        </h1>
      </header>
      <main>
        {children}
      </main>
    </div>
  )
}

Go ahead and try clicking between these pages a few times. Did you notice how smooth the transition back to the index page is? No? It was so smooth that you didn’t notice that there’s actually a 100ms delay? Great! That’s exactly the experience that your users want.

Here’s how it works: useCurrentRoute() returns the most recent completely loaded route. And useLoadingRoute() returns any requested-but-not-yet-completely-loaded route. Or if the user hasn’t just clicked a link, it returns undefined.

Want to display a loading bar while pages load? Then just call useLoadingRoute(), check if there’s a value, and render a loading bar if there is! CSS transitions let you do the rest.

#More neat tricks

I’m not going to drop the entire set of guides, API reference, and docs on integrating with other tools on you right now. You’re reading a blog post, so you might not have time for all that juicy information. But let me ask you a question:

What happens if the route doesn’t load?

One of the things about asynchronous data and views is that sometimes they don’t bloody work. Luckily, React has a great tool for dealing with things that don’t bloody work: Error Boundaries.

Let’s rewind for a moment to the <Suspense> tag that wraps your <View />. When <View /> encounters a not-yet-loaded route, it throws a promise, which effectively asks React to please show the fallback for a moment. You can imagine that <Suspense> catches that promise, and then re-renders its children once the promise resolves.

Similarly, if <View /> finds that getView() or getData() have thrown an error, then it re-throws that error. In fact, if the router encounters a 404-page-gone-for-a-long-stroll error, then <View /> will throw that, too. These errors can be caught by Error Boundary components. For the most part, you’ll need to make your own error boundaries, but Navi includes a <NotFoundBoundary> to show you how its done:

import BusyIndicator from '[email protected]'
import React from 'react'
import { Link, NotFoundBoundary, useLoadingRoute } from 'react-navi'

export default function Layout({ children }) {
  // If there is a route that hasn't finished loading, it can be
  // retrieved with `useLoadingRoute()`.
  let loadingRoute = useLoadingRoute()

  return (
    <div className="Layout">
      {/* This component shows a loading indicator after a delay */}
      <BusyIndicator isBusy={!!loadingRoute} delayMs={200} />
      <header className="Layout-header">
        <h1 className="Layout-title">
        <Link href='/'>
          Hats 'n' Flamethrowers 'r' Us
        </Link>
        </h1>
      </header>
      <main>
        <NotFoundBoundary render={renderNotFound}>
          {children}
        </NotFoundBoundary>
      </main>
    </div>
  )
}

function renderNotFound() {
  return (
    <div className='Layout-error'>
      <h1>404 - Not Found</h1>
    </div>
  )
}

#But that’s not all!

Ok, so I think we’re about out of time for this blog post. But there’s a bunch more details in the docs:

You can also check out the examples directory of the Navi repository for full code examples, including:

Oh, and did I mention that Navi is build with TypeScript, so the typings are first-class?

#Help me, Obi-Wan Kenobi. You’re my only hope.

Ok, so even if you’re not Obi-Wan Kenobi, I’d really appreciate your help.

Actually, a lot of little things are way more helpful than they might seem. Can you try Navi out and file an issue for any missing features? Awesome. Can you make tiny improvements to the docs as you learn? Radical. Can you put something small online and add it to the README's list of sites using Navi? Phenomenal.

With that said, there are a few big ticket items that I’d love some help with:

  • Navi needs some dev tools. Internally, all data is represented as simple objects called Chunks — which are then reduced into Route objects with a Redux-like reducer. As a result of this design, it should be possible for dev tools to provide a useful window into what’s going on, along with time-travel capability — but I want to leave this task for the community. So if you want to be the person who made Navi’s dev tools, let’s discuss the details 🤓

  • Matcher functions like mount(), lazy() and route() are just Generator Functions. In fact, it’s entirely possible to create custom matchers. For instance, you could create a withTimeout() matcher that switches routes based on how long they take to load. And if you do create useful custom matchers, send a tweet or DM to @james_k_nelson so I can spread the word 🤩

  • If you can provide a translation for even a single page from the docs, I’ll be forever grateful ❤️

  • If you’d like to see this project grow, please give it a 🌟Star on Github!

#One more thing…

Navi now has experimental server rendering support. Matchers like route() and mount() have access to an entire Request object, including method, headers, and body. Your routes aren’t limited to matching just a view and data — they can also match a HTTP status and headers.

You can now handle routing on the client, the server and in serverless functions with exactly the same code.

Of course, you could already do some of this with Next.js — but if all you need is a router, then Navi is a lot smaller (and more flexible). If you’d like to know more about the difference, take a read through Navi vs. Next.js. Or if you just want the server rendering demo:

import { createMemoryNavigation, mount, route, lazy } from 'navi'
import React, { Suspense } from 'react'
import ReactDOMServer from 'react-dom/server'
import { NaviProvider, View } from 'react-navi'
import api from './api'
import Landing from './Landing'
import Layout from './Layout'

async function main() {
  const routes =
    mount({
      '/': route({
        title: "Hats 'n' Flamethrowers 'r' Us",
        getData: (request) => {
          console.log('headers', request.headers)
          return api.fetchProducts()
        },
        view: <Landing />,
        status: 200,
      }),
      '/product': lazy(() => import('./product')),
    })

  // Creates a "navigation" object, which contains the same functionality
  // as the browser `<Router>` object, but handled in-memory.
  const navigation = createMemoryNavigation({
    routes,
    request: {
      headers: {
        'authorization-token': '123',
      },
      url: window.location.pathname
    }
  })

  // Wait for the navigation object to stabilise, so it can be rendered
  // immediately.
  await navigation.steady()

  console.log('status', navigation.getCurrentValue().status)

  // As `renderToString()` doesn't support `<Suspense>`, instead of using
  // a `<Router>` with a `<Suspense>`, you'll need to manually pass your
  // navigation object to a `<NaviProvider>` component.
  let html = ReactDOMServer.renderToString(
    <NaviProvider navigation={navigation}>
      <Layout>
        <View />
      </Layout>
    </NaviProvider>
  )

  document.body.innerHTML = html
}

main()

As of right now, there’s no official package for integrating Navi with Express. There should be one. Please make one. I’ll tell the world about it.

But seriously, I will tell the world about anything you make with Navi. Here’s how I’ll do it: the Frontend Armory weekly newsletter. Want to hear about awesome React shit that other readers are making? Join it. You know you want to.

Join Frontend Armory for Free »

But that’s it from me today. Thanks so much for reading. I’ve poured my heart into this project because I believe that it’ll make your life as a React developer so much easier. Now go build something amazing!

P.S. I haven’t forgotten about the React in Practice course — I’m working on it right now, and it’ll include hooks. I’ll have more more details real soon.

]]>
[email protected] (James K Nelson)
<![CDATA[useContext(): a React hook that's an obvious win]]> https:/frontarm.com/james-k-nelson/usecontext-react-hook/ https:/frontarm.com/james-k-nelson/usecontext-react-hook/ Wed, 06 Feb 2019 00:00:00 GMT

Earlier today, the React team released React 16.8, and along with it the eagerly awaited hooks API.

If you haven’t yet heard, React’s hooks API opens a up a whole new way of writing components - and the internet is abuzz with talk of the possibilities. Of course, with such a major change, many people are also asking the question: do we really need this new API?

In this article, I’m going to skip this question and instead try to answer something simpler and more useful: are there any situations where hooks are just obviously better? My answer is yes, and I think you’ll agree after seeing just how much useContext improves readability.

#Context 😕

Since React’s beginnings, one of the least satisfying parts of using it has been has been the process of passing data through many levels of your component tree. Initially, this could only be accomplished by prop drilling, i.e. manually passing props through every level of your tree. This was obviously cumbersome, so the React team give us an experimental Context API to work with, before releasing an official Context API early last year. The thing is, even the official Context API has its quirks.

After consuming data from a Context, you’ll typically only have access to the consumed data within a render function, as seen in this example.

import React from 'react'

const CurrentRoute = React.createContext({ path: '/welcome' })

export default function App() {
  return (
    <CurrentRoute.Consumer>
      {currentRoute => 
        currentRoute.path === '/welcome' &&
        "Welcome!"
      }
    </CurrentRoute.Consumer>
  )
}

In the above example, only a single piece of data is being consumed. And honestly, this looks ok. It’s easy enough to understand what’s going on. But imagine for minute that you want to consume values from three Context objects:

import React from 'react'

const CurrentRoute = React.createContext({ path: '/welcome' })
const CurrentUser = React.createContext(undefined)
const IsStatic = React.createContext(false)

export default function App() {
  return (
    <CurrentRoute.Consumer>
      {currentRoute =>
        <CurrentUser.Consumer>
          {currentUser =>
            <IsStatic.Consumer>
              {isStatic =>
                !isStatic &&
                currentRoute.path === '/welcome' &&
                (currentUser
                  ? `Welcome back, ${currentUser.name}!`
                  : 'Welcome!'
                )
              }
            </IsStatic.Consumer>
          }
        </CurrentUser.Consumer>
      }
    </CurrentRoute.Consumer>
  )
}

While this second example works, it’s starting to look unwieldy. You can see that there’s a callback pyramid starting to form – and the more context you consume, the worse it’s gonna get. Unless, that is, you use the new useContext() hook.

#useContext() 😆

Starting with React 16.8, you now have useContext(): a new, simpler way to consume data from multiple contexts. Here’s how you’d use it to simplify the above example:

import React, { useContext } from 'react'

const CurrentRoute = React.createContext({ path: '/welcome' })
const CurrentUser = React.createContext(undefined)
const IsStatic = React.createContext(false)

export default function App() {
  let currentRoute = useContext(CurrentRoute)
  let currentUser = useContext(CurrentUser)
  let isStatic = useContext(IsStatic)

  return (
    !isStatic &&
    currentRoute.path === '/welcome' &&
    (currentUser
      ? `Welcome back, ${currentUser.name}!`
      : 'Welcome!'
    )
  )
}

Neat, huh? But before moving on, I want you to try and imagine something for a minute.

Imagine that both of the above code examples are boring old APIs that you’ve been using for years.

Have you gotten in that frame of mind? Great! So I want to ask you a question:

Which API is clearer?

To me, the answer seems obvious. The second example wins the readability contest hands down. To bring back an old React cliché - it’s much easier to reason about.

Ok, so let’s come back to the read world for a moment (thanks for going through this exercise with me!) It’s February 2019, and hooks are brand spankin' new. They’re a big change, and there’s going to be a lot of uncertainty around them. But you now have at least one solid answer: hooks are definitely an improvement for consuming context.

So the next question is, what else are hooks good for? I’m as keen to find out as you are, and I’ll be making sure to share what I learn on this blog. Don’t want to miss it? Join Frontend Armory now to stay in the loop — it’s free!

In the meantime, if you’re interested in learning hooks then there’s a few resources you can check out:

Thanks so much for reading — it’s great to know that there are people like you who find this useful enough to read all the way to the end 😊 So until next time, happy engineering!

]]>
[email protected] (James K Nelson)
<![CDATA[Will it finally: a try/catch quiz]]> https:/frontarm.com/james-k-nelson/will-finally-run-quiz/ https:/frontarm.com/james-k-nelson/will-finally-run-quiz/ Mon, 04 Feb 2019 00:00:00 GMT

With the advent of async/await, I’ve recently found myself using a lot more try/catch/finally in my code. But honestly, I’m a little out of practice with finally. When I went to actually use it, I was a little unsure of its finer details. So I put together a few examples.

#When you throw a catch

Consider the case where you throw an exception within a catch block. There’s nothing to catch your throw before it exits the function. Does finally run?

To find out, just uncomment the example() call at the bottom of the editor!

function example() {
  try {
    fail()
  }
  catch (e) {
    console.log("Will finally run?")
    throw e
  }
  finally {
    console.log("FINALLY RUNS!")
  }
  console.log("This shouldn't be called eh?")
}

// example()
Spoiler

The finally runs, even though the last log statement doesn’t!

You can see that finally is a little special; it lets you run things between throwing an error and leaving the function, even if that error was thrown inside a catch block.

#Try without catch

Did you know that if you supply a finally block, you don’t need to supply a catch block too? You probably did, but it was worth asking!

So next question: does that finally block get called even if nothing goes wrong in the try block? If you’re not sure, uncomment the example() at the bottom of the editor to find out.

function example() {
  try {
    console.log("Hakuna matata")
  }
  finally {
    console.log("What a wonderful phrase!")
  }
}

// example()
Spoiler

Yep, finally is called even when nothing goes wrong. Of course, it also gets called when something does go wrong.

That’s the idea behind finally — it lets you handle both cases, as you can see in this example:

function example() {
  try {
    console.log("I shall try and fail");
    fail();
  }
  catch (e) {
    console.log("Then be caught");
  }
  finally {
    console.log("And finally something?");
  }
}

// example()

#Return and finally

So finally lets you clean up after yourself when exceptions occur. But what about when nothing goes wrong and you just return from the function like normal… in a try block?

Take a look at the below example. Is it possible that the finally block within example() can run after you’ve already hit a return statement? Uncomment the example() at the bottom of the editor to find out!

function example() {
  try {
    console.log("I'm picking up my ball and going home.")
    return
  }
  finally {
    console.log('Finally?')
  }
}

// example()

#The Rule

The finally block on a try/catch/finally will always run — even if you bail early with an exception or a return.

This is what makes it so useful; it’s the perfect place to put code that needs to run regardless of what happens, like cleanup code for error-prone IO. In fact, that’s what inspired this article.

#I used finally for…

Frontend Armory is a statically rendered website; it’s built with a tool called Navi, which lets you configure a renderPageToString() function that will be used to render each page.

In order to make sure each call to renderPageToString() is independent of the previous one, Navi uses try/catch/finally and some obscure node-fu to unload any modules that are loaded during the rendering process.

let oldCacheKeys = new Set(Object.keys(require.cache))
try {
  html = await renderPageToString(options)
}
catch (e) {
  throw e
}
finally {
  process.env.NODE_ENV = nodeEnv

  for (let key of Object.keys(require.cache)) {
    if (!oldCacheKeys.has(key)) {
      delete require.cache[key]
    }
  }
}

As you can see from the above example, try/catch/finally also work great with JavaScript’s new async/await syntax. So if this has reminded you that you need to brush up on async/await, now’s the time to mosey on over to my Mastering Asynchronous JavaScript course!

But that’s it for today. Thanks so much for reading! If you have any questions or comments, shoot me a Tweet or DM at @james_k_nelson. And until next time, happy coding :-)

]]>
[email protected] (James K Nelson)
<![CDATA[CSS-in-JS and Static Rendering]]> https:/frontarm.com/james-k-nelson/css-in-js-static-rendering/ https:/frontarm.com/james-k-nelson/css-in-js-static-rendering/ Sat, 02 Feb 2019 00:00:00 GMT

More and more developers are switching to CSS-in-JS, including big names like Microsoft, Atlassian, and… the Eurovision song contest! And while I haven’t always been a huge fan of CSS-in-JS, even I’m coming around to its benefits:

  • It lets you easily share variables between JavaScript and CSS (just don’t forget to escape them).
  • It’s a boon for tooling, making it easier to remove dead code, and to send the minimum amount of CSS possible.
  • And most importantly, it encourages writing CSS in a composable fashion.

It looks like CSS-in-JS will dominate the styling of web apps for the foreseeable future. But web apps only make up a fraction of the web, because content is still king — as the meteoric rise of Gatsby has made apparent.

As a React developer, there’s as good a chance as any that you’ll be working on statically rendered web sites. And as I discovered while building create-react-blog and Frontend Armory, using CSS-in-JS for statically rendered sites still comes with a few caveats…

#Avoiding Flashes Of Unstyled Content

The idea behind static rendering is to speed up a site by pre-rendering the HTML for each page, which can then be displayed to users before the JavaScript finishes loading. Of course, with CSS-in-JS, your styles are in, well, the JavaScript. And this presents a problem — the initial HTML will be unstyled until the JavaScript finished loading.

Luckily, the teams maintaining styled-components and emotion allow you to solve this with a little extra code. For instance, styled-components provides the ServerStyleSheet object, which allows you to statically render your styles at the same time as you statically render your HTML. Then, you just send the statically rendered <style> tag as part of your HTML:

import React from 'react@next'
import { renderToString } from 'react-dom@next/server'
import styled, { ServerStyleSheet } from 'styled-components'

// A styled component
const Button = styled.a`
  border: 2px solid palevioletred;
  border-radius: 3px;
  color: palevioletred;
  display: inline-block;
  font-family: sans-serif;
  padding: 0.5rem 1rem;
  margin: 0.5rem 1rem;
`

// The React element that will be statically rendered
const pageContent = (
  <Button
    as={'a'}
    href='https://www.youtube.com/watch?v=FpBJih02aYU'
    target='_blank'>
    Not my Gumdrop Buttons!
  </Button>
)

// `ServerStyleSheet` can collect styles from your statically rendered
// HTML, and then output them as a string of `<style>` tags.
const sheet = new ServerStyleSheet()
const html = renderToString(sheet.collectStyles(pageContent))
const styleTags = sheet.getStyleTags()

console.log('Static stylesheet:\n', styleTags)

document.getElementById('root').innerHTML = styleTags+html

By pre-rendering a <style> tag and sending it with your HTML, you’ll avoid the flash of unstyled content — but there’s a catch. As ServerStyleSheet only produces styles for the initial props, any use of component state, componentDidMount or componentDidUpdate will not be reflected in the server rendered styles. Given that your pre-rendered HTML has the same constraint, this shouldn’t be a problem. But if you do need a little help fetching the initial data for each of your app’s URLs, take a look at Navi — a router that was built with static/server rendering in mind. But I digress.

Statically rendering your styles has another benefit: it reduces the amount of CSS that’s required on each page’s initial load. This is because the rendered <style> tags only contain the critical CSS that is required for the pre-rendered HTML. The rest of the CSS is still managed with JavaScript, letting you split it out via dynamic import(). This can be great for performance… or it can result in many megabytes of CSS that is invalidated on every update — even for updates that don’t touch the content.

#Inline vs. External Stylesheets

If you take a look at the generated <style> tag in the above example, you’ll notice that it has a data-styled attribute. This is important, because it shows that styled-components is tied to that <style> tag. You can’t reliably extract the contents of that <style> tag into a CSS file referenced by <link>. Which is… maybe not that much of a problem?

I mean, why would you want to put your styles in a separate file anyway?

To answer this question, consider the main reason that you’d statically render in the first place: it lets you serve JavaScript from a CDN. Now the thing about assets served from a CDN is that they’re often cached with expiry dates in the far future. As such, changes to these assets require new filenames in order to bypass the cache.

Naturally, changes to the names of JavaScript files will require corresponding changes to the HTML that references them. As a result, your app’s HTML files can’t be cached as heavily — and neither can the <style> tags that are embedded in them. And due to the design of Webpack, changes to any JavaScript file in your project will usually require a change to every <script> tag, and thus HTML file, in your app.

<!-- For example, this script tag: -->
<script src="/static/js/runtime~main-47df755c101a4.js"></script>

<!-- Might change to this after fixing a typo: -->
<script src="/static/js/runtime~main-55ce84a0cc19b.js"></script>

For apps with few pages, little traffic, or small <style> tags, this is a non-issue. But for content-focused websites, the numbers can start to add up. For example, say that you’re running a site with 1000 pages, and with 25kb of critical CSS on each. Across all your HTML files, you’ll now have 25mb of CSS in <style> tags; and all of that CSS needs to be pushed to the CDN with every change to your site — even if your only change is to fix a typo!

#You can still use CSS-in-JS, though.

Is it a problem to have to push all of your inline CSS to a CDN with every change? Is it a problem if users can’t cache the critical CSS? The answer is — of course — it depends. In particular, there are three conditions which can cause issues:

  1. If you have many pages with a large amount of critical CSS
  2. If your content is frequently updated
  3. If your site gets a lot of traffic

In particular, if your site meets all three of these conditions, then there’s a good chance that you can improve performance (and save on hosting costs) by moving some of your CSS out to separate CSS files. Keep in mind that you can continue using CSS-in-JS alongside plain CSS or CSS Modules — you’ll just want to keep the size of your critical CSS manageable.

Of course, styled-components isn’t the only kid on the block. The next most popular tool, emotion, has much the same story as styled-components. But there’s also linaria — a CSS-in-JS tool that is more focused towards static rendering. If you want to use CSS-in-JS, but styled-components doesn’t suit your requirements, then linaria is definitely worth checking out!

But maybe your heart is set on styled-components — after all, it’s got an all-star team and a huge community. And importantly, it’s open source, so you can help out! The styled-components team is currently working to make it possible to extract cacheable CSS — so if you’d like to chip in, take a look at this Pull Request.

Lastly, it must be said that while CSS-in-JS is a great option, it’s not a necessity. CSS Modules and SASS solve most of the same issues while working out of the box with create-react-app and create-react-blog. Both CSS-in-JS and plain CSS have their place, and knowing the ins and outs of both will help you pick the right tool for the job.


Have you noticed how ridiculously fast Frontend Armory is? While building it, I’ve spent gobs of time learning the ins and outs of static rendering and code splitting, and now I want to save you the trouble of doing the same. So. If you’re building a React app and speed affects your bottom line (or you just want a snappy UI), then you need to see my upcoming course: React in Practice. More details are coming soon; join Frontend Armory now to be the first to find out — it’s free!

]]>
[email protected] (James K Nelson)
<![CDATA[Reusable Time Travel with React Hooks and Immer]]> https:/frontarm.com/swyx/reusable-time-travel-react-hooks-immer/ https:/frontarm.com/swyx/reusable-time-travel-react-hooks-immer/ Wed, 30 Jan 2019 00:00:00 GMT

Bottom Line Up Front: You’ll learn how to build this demo — with a useTimeTravel React hook.

import React from 'react';
import { useTimeTravel } from './useTimeTravel';

const initialState = { x: 0, y: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'RESET':
      return initialState;
    case 'MOVE':
      state.x += action.x;
      state.y += action.y;
      state.x = Math.min(Math.max(state.x, 0), 9);
      state.y = Math.min(Math.max(state.y, 0), 9);
  }
}

export default function App() {
  const { state, dispatch, timeline, doUndo, doRedo, doReset } = useTimeTravel(
    reducer,
    initialState
  );
  const createMove = (x, y) => () => dispatch({ type: 'MOVE', x, y });
  return (
    <div>
      <h1>Move the green box around</h1>
      <div id="App">
        <div className="redBox" style={{ '--stateX': `${state.x}0px`, '--stateY': `${state.y}0px` }}>
          <div className="greenBox" />
        </div>
        <div className="arrows">
          <div />
          <button onClick={createMove(0, -1)}>🔼</button>
          <div />
          <button onClick={createMove(-1, 0)}>⬅️</button>
          <div>⭐</div>
          <button onClick={createMove(1, 0)}>➡️</button>
          <div />
          <button onClick={createMove(0, 1)}>🔽</button>
          <div />
        </div>
      </div>
      <hr />
      <button onClick={doUndo} disabled={timeline.past.length === 0}>
        Undo
      </button>
      <button onClick={doRedo} disabled={timeline.future.length === 0}>
        Redo
      </button>
      <button
        onClick={doReset}
        disabled={timeline.past.length === 0 && timeline.future.length === 0}
      >
        Reset
      </button>
      <hr />
      <ul>
        <li>Past: {JSON.stringify(timeline.past)}</li>
        <li>Present: {JSON.stringify(timeline.present)}</li>
        <li>Future: {JSON.stringify(timeline.future)}</li>
      </ul>
    </div>
  );
}

React Hooks are a fundamentally simpler way to encapsulate custom behavior in user interfaces.

If stateful React components are like an atom, hooks are the subatomic particles. We are given primitives like useState and useReducer, and we can compose and remix them in various quantities to create new elements with the exact properties we want.

Where useState is useful for reading and mutating atomic values, useReducer is better for updating collections (arrays and objects) of data that represent more complex states. It borrows heavily from Redux patterns in dispatching typed actions and passing through simple state machines. I will refer the reader to the docs rather than repeat them here.

#Tolerant User Interfaces

My favorite of the six principles of User Interface Design is Tolerance, which asks the UI designer to limit the cost of mistakes by the user. By giving the user an implicit assurance that their work won’t be lost without intention, they encourage play and discovery of everything else in the UI, which enables more serendipity with lower cognitive load. Many apps I see don’t pass this simple test, and don’t offer undo/redo capability even in UI that doesn’t interact with a backend, probably because it is extra work.

We should make it easier to write Tolerant User Interfaces.

One easy way to reduce the number of irreversible actions is to make more things reversible. Implementing this with typical state primitives in React is troublesome, because those APIs tend to discard past state in favor of new state.

#Implementing a Timeline

So how do we implement tolerance in our React apps? We can stick historical state in another piece of state, or a global variable, but those solutions are problematic too. Better to treat state history just like another part of state:

  const timeline = {
    past: [],
    present: initialState,
    future: []
  };

Because we’re working with objects and arrays, we’d like to avoid defensive copying and use local mutability with structural sharing, so we introduce immer:

import produce from 'immer'

(seriously, go read the docs)

And now we can write reducer methods to add new states:

function _addNewPresent(timeline, newPresent) {
  return produce(timeline, draft => {
    draft.past.push(draft.present);
    draft.present = newPresent;
    draft.future = [];
  });
}

and move back in time:

function _doUndo(timeline) {
  return produce(timeline, draft => {
    if (!draft.past.length) return;
    const newPresent = draft.past.pop();
    draft.future.unshift(draft.present);
    draft.present = newPresent;
  });
}

and Redo and Reset and so on.

#Proxying useReducer with the Timeline

Now that we’ve scoped out our Timeline data structure, we can think a bit about the reusability of it, and try to build it in to an idiomatic custom React Hook.

The useReducer API looks like this:

const [state, dispatch] = useReducer(reducer, initialState);

Wouldn’t it be nice if we could pass in a similar reducer to a different hook?

const { state, dispatch, timeline, doUndo } = useTimeTravel(reducer, initialState);

And we could write the reducer in a locally mutable style?

function reducer(state, action) {
  switch (action.type) {
    case 'RESET':
      return initialState;
    case 'MOVE':
      state.x += action.x;
      state.y += action.y;
  }
}

In order to accomplish this, we need to transform reducer and initialState into the timeline data structure, and then return nicely named, easy to work with variables in the result. This is trivial in custom hooks:

export function useTimeTravel(reducer, initialState) {
  const timeline = {
    past: [],
    present: initialState,
    future: []
  };
  const proxiedReducer = (tl, action) => {
    if (action === UNDO) return _doUndo(tl);
    if (action === REDO) return _doRedo(tl);
    if (action === RESET) return _doReset(tl);
    // else
    const newState = produce(tl.present, draft => reducer(draft, action));
    return _addNewPresent(tl, newState);
  };
  const [_timeline, _dispatch] = useReducer(proxiedReducer, timeline);
  return {
    state: _timeline.present,
    timeline: _timeline,
    dispatch: _dispatch,
    doUndo: () => _dispatch(UNDO), // nice to wrap action type
    doRedo: () => _dispatch(REDO), // nice to wrap action type
    doReset: () => _dispatch(RESET) // nice to wrap action type
  };
}

So working backwards from the API that we want to use, we were able write the custom hook logic in just a few lines of code.

We can use the destructured artefacts in our UI easily:

const createMove = (x, y) => () => dispatch({ type: 'MOVE', x, y });
// later on...
<button onClick={createMove(0, -1)}>🔼</button>
<button onClick={createMove(-1, 0)}>⬅️</button>
<button onClick={createMove(1, 0)}>➡️</button>
<button onClick={createMove(0, 1)}>🔽</button>
<button onClick={doUndo} disabled={timeline.past.length === 0}>
  Undo
</button>
<button onClick={doRedo} disabled={timeline.future.length === 0}>
  Redo
</button>
<button
  onClick={doReset}
  disabled={timeline.past.length === 0 && timeline.future.length === 0}
>
  Reset
</button>

And you can play with it here:

import React from 'react';
import { useTimeTravel } from './useTimeTravel';

const initialState = { x: 0, y: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'RESET':
      return initialState;
    case 'MOVE':
      state.x += action.x;
      state.y += action.y;
      state.x = Math.min(Math.max(state.x, 0), 9);
      state.y = Math.min(Math.max(state.y, 0), 9);
  }
}

export default function App() {
  const { state, dispatch, timeline, doUndo, doRedo, doReset } = useTimeTravel(
    reducer,
    initialState
  );
  const createMove = (x, y) => () => dispatch({ type: 'MOVE', x, y });
  return (
    <div>
      <h1>Move the green box around</h1>
      <div id="App">
        <div className="redBox" style={{ '--stateX': `${state.x}0px`, '--stateY': `${state.y}0px` }}>
          <div className="greenBox" />
        </div>
        <div className="arrows">
          <div />
          <button onClick={createMove(0, -1)}>🔼</button>
          <div />
          <button onClick={createMove(-1, 0)}>⬅️</button>
          <div>⭐</div>
          <button onClick={createMove(1, 0)}>➡️</button>
          <div />
          <button onClick={createMove(0, 1)}>🔽</button>
          <div />
        </div>
      </div>
      <hr />
      <button onClick={doUndo} disabled={timeline.past.length === 0}>
        Undo
      </button>
      <button onClick={doRedo} disabled={timeline.future.length === 0}>
        Redo
      </button>
      <button
        onClick={doReset}
        disabled={timeline.past.length === 0 && timeline.future.length === 0}
      >
        Reset
      </button>
      <hr />
      <ul>
        <li>Past: {JSON.stringify(timeline.past)}</li>
        <li>Present: {JSON.stringify(timeline.present)}</li>
        <li>Future: {JSON.stringify(timeline.future)}</li>
      </ul>
    </div>
  );
}
]]>
<![CDATA[4 ways to pass children to React elements]]> https:/frontarm.com/james-k-nelson/4-ways-pass-children-react-elements/ https:/frontarm.com/james-k-nelson/4-ways-pass-children-react-elements/ Mon, 28 Jan 2019 00:00:00 GMT

Did you know that React gives you no less than four different ways to specify the children for a new React Element?

#1. Nesting JSX

To start with, there’s the obvious way: nesting the elemen’s between its start and end tags, like the blue div in this example:

ReactDOM.render(
  <div className="red">
    <div className="blue" />
  </div>,
  document.querySelector('#root')
)

The obvious approach is… kinda obvious. But it gives you a hint to approach number two. Given that JSX compiles to JavaScript, there must be a pure JavaScript way to do the same thing. And while there’s a good chance that you already know the corresponding vanilla JavaScript, if you don’t, you can find out by clicking on the Compiled button in the above editor.

And if you do click on the Compiled button, you’ll see a couple calls to…

#2. createElement()

JSX elements in a React project are transformed at build time into calls to React.createElement(). This function’s first two arguments represent the elment’s type and props, while any subsequent arguments represent the element’s child nodes.

React.createElement(
  type,
  props,

  // You can pass as many children as you need - or none at all.
  childNode1,
  childNode2,
)

For example, the two elements in the above JSX transpile to two separate calls to React.createElement():

React.createElement(
  "div",
  { className: "red" },
  React.createElement("div", { className: "blue" })
)

There are three important things to understand about React.createElement():

  1. It returns a plain old JavaScript object that contains all of the information that you passed into it.
  2. It’s first two arguments represent type and props, and any further arguments represent its children.
  3. You can pass as many children as you’d like… or none at all.

Simple, huh? But there’s one curious thing about the object returned by React.createElement(). While the returned object has properties corresponding to the type and props arguments, it doesn’t have a children property. Instead, the children are stored on props.children.

console.log(
  React.createElement(
    "div",
    { className: "red" },
    "Hello, friend!"
  )
)

So what happens if you pass React.createElement() both a children prop along with the children argument? Let’s find out!

console.log(
  React.createElement(
    "div",
    {
      children: "Props win!",
      className: "red",
    },
    undefined
  )
)

As you can see in the above editor’s console, the children prop is ignored in favor of the value passed via argument — which happens to be undefined. But this raises a question: what would happen if you didn’t pass a third argument?

This leads us to the third way to specify an element’s children.

#3. Pass a children prop to createElement()

When you pass a children prop to createElement(), without passing third (or subsequent) arguments, then that will become the element’s children.

ReactDOM.render(
  React.createElement('div', {
    children: React.createElement('div', {className: "blue" }),
    className: "red",
  }),
  document.querySelector('#root')
)

This has an interesting corollary: you can also pass elements via props other than children. In fact, you can pass multiple elements to a component using multiple props. This pattern is sometimes called slots — and you can learn more about it with Dave Ceddia’s guide to slots.

Of course, you don’t have to use raw JavaScript to pass a children prop — which leads to the 4th and final way to specify an element’s children…

#4. Pass a children prop with JSX

Just as we started by transforming a JSX element into a call to createElement(), let’s finish by rewriting the above with JSX:

ReactDOM.render(
  <div
    children={<div className="white" />}
    className="black"
  />,
  document.querySelector('#root')
)

#Ok, but… whhhy?

Putting aside the question of whether you can pass children via props (you can), let’s ask a perhaps more important question: should you?

It goes without saying that usually, it’s clearer to specify a JSX element’s children the standard way. But with that said, there are a couple situations where the ability to specify children as a prop comes in handy.

#1. Consuming Contexts

When working with React context, you’ll run into a small problem when you need to consume values from multiple contexts: you need to nest context consumers within each other to access multiple values. And so just when you thought that Promises and async/await had banished callback pyramids from the idyllic land of JavaScript forever, you end up with this:

function InvoiceScreen(props) {
  return (
    <RouteContext.Consumer>
      {route =>
        <AuthContext.Consumer>
          {auth =>
            <DataContext.Consumer>
              {data =>
                <InvoiceScreenImpl
                  route={route}
                  auth={auth}
                  data={data}
                  {...props}
                />
              }
            </DataContext.Consumer>
          }
        </AuthContext.Consumer>
      }
    </NavRoute>
  )
}

The above code can be shortened by using the children prop, instead of nesting JSX elements:

function InvoiceScreen(props) {
  return (
    <RouteContext.Consumer children={route =>
      <AuthContext.Consumer children={auth =>
        <DataContext.Consumer children={data =>
          <InvoiceScreenImpl
            route={route}
            auth={auth}
            data={data}
            {...props}
          />
        } />
      } />
    } />
  )
}

Of course, this still isn’t perfect. For perfection, you’ll need to wait for the new React Hooks API, which will make consuming context a breeze.

#2. Passing Through Props

Suppose that you have a component that just wraps another component — possibly transforming the props in some way, before passing them through to a child component.

In fact, you may have just seen such a component. To see what I mean, let me transform the previous InvoiceScreen example into plain JavaScript.

function InvoiceScreen(props) {
  return (
    createElement(RouteContext.Consumer, { children: route =>
      createElement(AuthContext.Consumer, { children: auth =>
        createElement(DataContext.Consumer, { children: data =>
          createElement(InvoiceScreenImpl, {
            route,
            auth,
            data,
            ...props
          })
        })
      })
    })
  )
}

You’ll notice that each calls to createElement() in the above example only uses two arguments, so any value for props.children will be passed through to <InvoiceScreenImpl>.

When you think about this, it makes a lot of sense. It would be confusing to have to specifically pass the children prop through. And luckily, you don’t have to — because React lets you specify children in an appropriate way for the situation!


Have anything to add to this article? Let me know in the Twitter discussion!

]]>
[email protected] (James K Nelson)
<![CDATA[React Fragments in Practice – 4 real-world examples]]> https:/frontarm.com/james-k-nelson/react-fragments-in-practice/ https:/frontarm.com/james-k-nelson/react-fragments-in-practice/ Wed, 23 Jan 2019 00:00:00 GMT

When working with React, there are times when you’ll want to pass around groups of React elements. And while it used to be that doing so required you to add useless container components or confusing arrays, React solved this last year by introducing Fragments — a simple way to group elements without adding any extra markup.

ReactDOM.render(
  <ul>
    <React.Fragment>
      <li>The fragment element is not rendered to the DOM.</li>
      <li>
        You can confirm this by right clicking on one of these items
        in the preview pane, and inspecting the markup in the browser
        dev tools.
      </li>
    </React.Fragment>
  </ul>,
  document.querySelector("#root")
)

React.Fragment — as used in the above example — is like a markupless component. When rendered to the DOM, its children will be rendered by themselves, making it possible to pass around groups of elements without introducing unnecessary markup. Fragments are also great for working with table and list markup (like the above), where it’s just not possible to add an extra <div>.

#<>Fragment syntax</>

After using fragments for a while, you may run into an eensy-weensy issue: typing out <React.Fragment> is bothersome compared to typing <div>. And while this won’t get in the way when fragments are truly necessary, it certainly can slow down adoption. Which is why, I suppose, fragments also come with a concise new syntax:

ReactDOM.render(
  <>
    <h1>Yo Dawg,</h1>
    <p>
      I heard you like fragments so
      I <>put a <>fragment</> in your fragment</>.
    </p>
  </>,
  document.querySelector("#root")
)

As you can see, the <> and </> tags in JSX now correspond to <React.Fragment> and </React.Fragment>. There’s nothing else special about them — they compile down to the same thing as any other React element, with a type of React.Fragment:

React.createElement(
  React.Fragment,
  null,
  ...childElements
)

rover

When fragments were first released, there wasn’t much support for this syntax. But now that a year has passed, most major tools support it, including:

  • Babel 7+
  • TypeScript 2.6+
  • Prettier 1.9+
  • ESLint 3+ (along with babel-eslint 7)

Of course, you don’t have to worry about any of this if you’re using create-react-app, because it has supported fragments from when they were first released!

#Typical uses

Fragments have now had plenty of time for them to make their way into real world codebases. I’ve taken a look through a few open source projects to see how Fragments are being used in practice — and found a number of common use cases:

#1. Returning groups of elements

You can use fragments to create components that return a list of elements without wrapping them in a container or array. This is useful for components that return form and text markup — as wrapping the result in a container <div> can cause headaches when styling things.

Spectrum's source frequently uses fragment-returning components for this purpose. For example, take a look at the e-mail confirmation component:

class UserEmailConfirmation extends React.Component {
  render() {
    const { emailError, email, isLoading } = this.state;
    const { user } = this.props;

    return (
      <React.Fragment>        <EmailForm
          defaultValue={email}
          loading={isLoading}
          onChange={this.handleEmailChange}
          onSubmit={this.init}
          style={{ marginTop: '8px', marginBottom: '8px' }}
        />

        {user.pendingEmail && (
          <Notice>
            A confirmation link was sent to {user.pendingEmail}. Click
            the confirmation link and then return to this page. You can
            resend the confirmation here, or enter a new email address.
          </Notice>
        )}

        {emailError && <Error>{emailError}</Error>}
      </React.Fragment>    )
  }
}

Similarly, you can use fragments to return groups of elements from render functions. Wordpress’ Calypso frontend frequently uses this pattern to inject a translate function for internationalization:

<Step name="my-sites" target="my-sites" placement="below" arrow="top-left">
  { ( { translate } ) => (
    <Fragment>      <p>
        { translate(
          "{{strong}}First things first.{{/strong}} Up here, you'll " +
            "find tools for managing your site's content and design.",
          {
            components: {
              strong: <strong />,
            },
          }
        ) }
      </p>
      <Continue click icon="my-sites" step="sidebar" target="my-sites" />
    </Fragment>  ) }
</Step>

#2. Conditionally rendering groups of elements

Fragments make it far easier to conditionally render whole groups of elements without adding unnecessary markup. For example, they can be used with the ternary operator to switch an element’s content depending on the value of a prop:

export function ResetPasswordScreen({ hasPassword, name, ...formProps }) {
  return (
    <Layout>
      {hasPassword ? (
        <>          <h3>Reset your password</h3>
          <p>
            To finish resetting your password, enter your new password
            here and hit the "Reset" button.
          </p>
        </>      ) : (
        <>          <h3>Hi {name}!</h3>
          <p>Thanks for joining!</p>
          <p>
            Just one more step - please pick a password for your account:
          </p>
        </>      )}
      <ResetPasswordForm {...formProps} />
    </Layout>
  )
}

#Fragments with arrays

Fragments have one more powerful feature, which I’ve saved until last as it is rarely used. But when you do need this feature, it is invaluable:

Fragments can have key props!

<React.Fragment key='somevalue'>
  ...
</React.Fragment>

Why would you want to give a Fragment a key? Well, it allows fragments to be used as items in arrays. Which in turn makes it possible to splice elements into text — and all without introducing any unnecessary markup.

For example, the console view in Frontend Armory’s Demoboard editor uses keyed fragments to replace newline characters with <br> elements… and the resulting code is small enough that it would make for a great exercise!

See if you can use React Fragments to render the newline characters in the below string as <br> tags, without introducing any extra markup.

Once you’ve given it a try, you can take a look at my solution by clicking the Solution tab at the bottom of the editor.

let message = `
  Hello, there!
  HTML doesn't render new line characters by default,
  but you can add them back in as <br> tags!
`

// You'll need to replace the line break characters in this string
// with `<br>` elements.
let messageWithLineBreaks = message

ReactDOM.render(
  <div>{messageWithLineBreaks}</div>,
  document.querySelector('#root')
)

Thanks so much for reading! And if you know of any more uses for React Fragments, make sure to let everyone know in the twitter discussion!

]]>
[email protected] (James K Nelson)
<![CDATA[Using MDX with create-react-app 2]]> https:/frontarm.com/james-k-nelson/mdx-with-create-react-app/ https:/frontarm.com/james-k-nelson/mdx-with-create-react-app/ Sun, 16 Dec 2018 00:00:00 GMT

MDX is a wonderful way to write content for React-based apps. It gives you the succinct syntax of Markdown, with all the power of raw JSX. And while MDX started out as an obscure little package, it’s grown to be supported by everything from Next.js, to Gatsby, to mdx-deck.

But there’s one place where support has been conspicuously missing: create-react-app 2. Here’s why.

#Configuring create-react-app

While create-react-app 1 allowed for slight modifications to configuration through react-app-rewired, this wasn’t supported by the create-react-app team itself.

With create-react-app 2, official support was added for some extensions through babel-plugin-macros. In fact, it’s possible to get some MDX support with babel-plugin-macros through the mdx.macro package (by yours truly). However, this package has a major drawback: you’ll need to manually restart the server each time you change an .mdx file.

In order to implement proper MDX support through babel-plugin-macros, babel itself will need a new feature. But this feature doesn’t exist yet. So how are you going to get the benefit of MDX without ejecting from create-react-app?

#react-scripts-mdx

One of the great things about create-react-app is that it doesn’t force you to use the official scripts. It makes it dead easy to use a fork. And given that there’s now a react-scripts-mdx fork, this means that getting started with MDX and create-react-app is a one-liner:

Unimplemented.

Simple, huh? Or if you’ve already got a create-react-app generated project, you can add MDX support by just switching out react-scripts with react-scripts-mdx in your dependencies and running yarn install or npm install. Then, you’ll be able to add MDX files like this to your project:

# I'm a Markdown file

And I can use <em className="jsx">JSX!</em>

Then import and use your MDX file, just as you would with any other React component:

import React, { Component } from 'react';
import './App.css';
import MDXDocument from './test.md';

class App extends Component {
  render() {
    return (
      <div className="App">
        <MDXDocument />
      </div>
    );
  }
}

export default App;

Neat, huh? But while adding MDX support is super easy, is it really ok to use a fork?

#What the fork changes

The react-scripts-mdx fork makes a single change to react-scripts:

react-scripts-mdx will transform .md and .mdx files with mdx-loader.

The fork is tested, and is only a tiny patch on the main create-react-app project — making maintenance easy. Of course, the fork shouldn’t be necessary forever! Once babel-plugin-macros gains live reload support, it’ll be simple to transition over to that instead.

But for the moment, if you need MDX and create-react-app? Give react-scripts-mdx a try!

Thanks for reading! And if you have any questions, give me a shout on twitter at @james_k_nelson. And until next time, happy mdxing!

]]>
[email protected] (James K Nelson)
<![CDATA[Static vs. Server Rendering]]> https:/frontarm.com/james-k-nelson/static-vs-server-rendering/ https:/frontarm.com/james-k-nelson/static-vs-server-rendering/ Sat, 15 Dec 2018 00:00:00 GMT

So you’ve heard the terms static and server rendering. You know that they both improve SEO and involve generating HTML for your website or app. And given that you’re using React, then ReactDOMServer.renderToString() lets you accomplish either.

So they’re basically the same thing, right? Well, they’re aaalllmost the same. Let me explain.

#Static rendering is eager, server rendering is lazy

Both static and server rendering involve generating HTML for each of your site’s URLs. The difference is that static rendering happens once at build time, while server rendering happens on-demand, as the user requests each file.

#Static rendering

With static rendering, you’ll need to generate a single HTML file for every page that the user can access ahead of time. You’ll then serve these pages from a cloud service like S3, or from a server running something like nginx.

static rendering diagram

Static rendering has the advantage of being able to serve requests stupidly fast, because nothing needs to be generated on the fly. In fact, since your site’s responses are all generated ahead of time, you can store the files all over the world on a CDN (on the edge). This gives your site ridiculously fast response times. But there’s a catch.

With static rendering, you need to generate responses for every possible request ahead of time. For websites focussed on high quality content, this is fine — static renderers like Navi can generate hundreds of pages in mere seconds. But what if you’re building something where you can’t predict all possible requests, like a search engine? Or what if you have a lot of user generated contend, and the response changes on every request? In that case, you’ll need server rendering.

#Server rendering

In the React world, server rendering refers to the process of generating HTML on demand for each request. Usually, you’ll accomplish this by setting up a server running something like express or Next.js that renders your React app with each request — just as with a more traditional PHP or Rails based website.

server rendering diagram

Server rendering is always slower than serving static content. However, you’d need to mess things up pretty badly for the slowdown to be anything greater than a second — and whether this kind of delay matters really depends on your business requirements.

Of course, for what server rendering lacks in speed, it makes up for in flexibility. It allows you to:

  • Respond to any request that the user makes — even ones you might not have expected.
  • Pull the most recent content from a database, instead of server older static files.
  • Selectively hide content from unauthenticated users.

#So which should I use?

The answer is — of course — it depends.

If static rendering is possible, it’ll give you a faster, cheaper, simpler solution. However, if your site needs to serve HTML that meets any of these requirements, then you’ll need server rendering:

  • If you can’t predict all possible requests
  • If the response changes depending on who is viewing it
  • If responses quickly go out of date

Keep in mind that these requirements will only make server rendering necessary if you need to serve specific HTML for each page for SEO purposes. For example, a social network or online marketplace would best be built as a server rendered site.

On the other hand, if you’re building something where SEO is irrelevant — e.g. an app that lives behind a login screen — then your app only needs a single HTML file. It used to be that this was by far the simplest option, as it meant that you could just use stock create-react-app. However, recent improvements in static and server rendering tooling have mostly closed the simplicity gap.

#Rendering tooling

When I first started building websites with React a couple years ago, static/server rendering was fucking hard. I even wrote an article telling you don’t do it. But things have changed a lot.

There are a growing number of tools for statically rendering React-based websites and apps. Gatsby is a popular, heavy-duty option. For something simpler, you can try Navi, which drives this website and works alongside create-react-app.

As for server rendering, you have two options: the Next.js way, and the Express way. With Next.js, you get an entire framework and a hosting solution that works out of the box — but you tie your project to Next.js (who have stated that they will not provide an option to eject). If this doesn’t work for you, then you can always set up a more traditional Express app (and Navi’s router makes this easier than ever!)

#A little trivia

Let me close by explaining how the site that you’re reading right now works. Frontend Armory is statically rendered. Each time the content changes, the site is re-built using Navi, then pushed to S3. Then, when you send a request, it first checks for a cached version that is geographically close to you with CloudFront, before requesting it from S3 if that fails.

And that’s why Frontend Armory feels so snappy — it’s all about routing and static rendering!

Want to build a blinding fast website with great SEO? I’ll be launching a new course walking you through the process of building and deploying a statically rendered site with Navi and create-react-app later this month. Sign up to make sure you don’t miss it!

]]>
[email protected] (James K Nelson)
<![CDATA[Navi: SEO & routing with vanilla create-react-app]]> https:/frontarm.com/james-k-nelson/announcing-navi/ https:/frontarm.com/james-k-nelson/announcing-navi/ Wed, 12 Dec 2018 00:00:00 GMT

Businesses live and die on their web traffic, most which comes from search engines and social media. If you’re getting paid to build websites or web apps, then you need to think about SEO and SMO — it’s just how the world works.

Now if you were building an old-school PHP or Rails app, SEO would be free and SMO would be easy — you’d just add some meta tags to the <head> of your HTML files. But the future belongs to serverless React, and this presents a problem. You want to build a beautiful, interactive site, but you don’t want to have to eject from create-react-app to do it.

TL;DR? Jump to the docs or the code.

The thing is, React just wasn’t built to do SEO by itself. Sure, it has a renderToString() method… but it doesn’t support most lifecycle methods. And while server-side Suspense is coming, it’s been coming for a year and there’s still no release date.

So here’s the deal: you’re getting paid to build websites. You need to build traffic now — but you don’t want to reimplement everything yet again 6 months down the track. And you’re not alone, so let’s do something about it.

#Have your cake and eat it too

Today I’m releasing Navi: the router and static renderer that drives Frontend Armory. Navi lets you create big, fast, CDN-delivered websites with great SEO & SMO, and all with vanilla create-react-app. Of course, Navi also works great after ejecting, or even with an express-based app. No matter how you use it, you’ll save gobs of time with:

🔥 Simple loading transitions for async content
🗺️ JSON site maps that can be built at runtime or build time
⚠️ Console warnings when a <Link> points to a 404
📜 Scroll management that just works
♿️ Page <title> management for accessibility
🏷️ Great TypeScript support
👌 A dead-simple API

#Many hands make light work

Navi has around 2 years of history behind it, and its overarching design has barely changed over that time. It’s React integration was designed to work great with React Suspense - so when it arrives, your app will spontaneously grow a number of new features. And of course, Navi is 100% open source and open to contributions. Here are a few ways you could help:

  • Try it out and open an issue with your feedback 😄
  • Build the Vue integration (The navi package itself is vanilla JavaScript, and it’ll work just as well with Vue as it does with React)
  • Use the edit this page links to improve pages in the documentation

Speaking of documentation — the Navi website is 100% open source, and built with Navi and React itself. If you want to run it locally, just clone the navi-website repository, then run yarn install and yarn start and you’ll be good to go! But if you view them on Frontend Armory, you’ll get an extra special feature…

#All I want for Christmas is amazing documentation

Navi’s docs are choc-full of example code. And when viewing the docs as a Frontend Armory Pro member, many of these examples will be interactive demoboards — allowing you to quickly try out new things, and easily share the result with colleagues and friends. Pro members will also gain access to docs on niche topics like integrating Navi with react-router or react-helmet — helping to support development, and giving you peace of mind about the project’s sustainability into the future.

Of course, all of the documentation will still be completely open source, and available for you to fork and edit at your pleasure. In fact, the first three docs are already available, and I’ll be releasing a new page each day until Christmas. Here’s the plan:

  • Coming soon: Generating JSON site maps (pro exclusive)
  • 🎄 Christmas Day: it’s a surprise 😉

I’ll be linking each of these pages as they’re released, so check back each day to get a brand new link! ⏱

Thanks so much for reading! Given that you’ve read all this way, you really should give Navi a try — just head on through to A Minimal Example in the docs to try it out within the browser. And once you’re done, let me know your thoughts! Just open an issue, or send me a tweet at @james_k_nelson. Finally, if you decide to use Navi in your project, make sure to join Frontend Armory Pro to unlock access to the demoboards and integration docs.

See you again on Christmas Day with a Navi surprise! 🎁

]]>
[email protected] (James K Nelson)