Build and launch a Modern WebApp - workshop by Swizec

modernwebapp.dev

The tools

You can read this segment in in 8 minutes. Solving the exercises might take longer.

This segment covers πŸ‘‡

Tech & Libraries we're using today

We're building a modern app and that requires modern tools. Here's what we're gonna use:

React is implied.

  • Gatsby for the web
  • Rebass for pre-built components and design system
  • React Hooks for all business logic
  • React-spinners for loading states
  • GraphQL to communicate with the server and the filesystem
  • ApolloClient for easy GraphQL on the web
  • ApolloServer to help us with GraphQL on the server
  • AWS Lambdas to run the server
  • AWS DynamoDB to store data
  • AWS S3 to store images
  • Serverless framework to manage AWS
  • NodeJS with TypeScript for server-side code

Gatsby in a nutshell

Gatsby is a static site generator for React. You can think of it as done-for-you server-side rendering, speed optimizations, offline capabilities, and GraphQL interface. It's quite lovely.

Gatsby's killer feature is the blog example - a quick way to build a blog that takes markdown files as input, renders them as React, and creats a static site that works offline without JavaScript. This workshop page is built with Gatsby. So are many of my other mostly-static websites.

I like the flexibility of working with React instead of raw HTML, love the great support for markdown and MDX, and have found Gatsby to be a great starting point for modern webapps. As Kyle Matthews, the founder of Gatsby, likes to say "We have a whole team working on making your websites fast, you should focus on the features"

As far as longevity goes, I'm comfortable betting on Gatsby because it's been around since 2015, keeps getting better, and it's both opensource and has a VC-backed team dedicated to keeping it running. Looks like Gatsby is here to stay πŸŽ‰

There's also a slew of plugins for all sorts of features and a wonderful community.

We're going to use Gatsby today to build our frontend and lean on its features to give us PWA capabilities out of the box. We won't go into detail on how Gatsby achieves these things.

You don't need to know the details. Leave that to the core team and lean into their expertise ✌️

PS: Gatsby also creates a great dev experience out of the box. You get hot code swapping, a local server, and even a GraphQL playground.

Rebass in a nutshell

Rebass is one of the many opensource React design systems I've tried. I like this one because it has great support for theming, a wonderful API for building responsive designs, and good enough defaults in the preset theme.

Rebass is based on styled-components and styled-system. This means you can use the rather intuitive built-in API for almost everything, yet still have the escape hatch to use CSS overrides for anything in particular.

Theming support means you can define common values once and your whole app adapts. Ideally this means once you configure your design, everything automatically looks correct according to your designer's dreams, even though you're thinking in mockups and interactions. Pretty neat 🀘

Hooks in a nutshell

Copied from a blogpost, ignore time-based references :)

React hooks took the React world by storm this weekend. They're not even out yet! And yet here we are.

JavaScript lyfe: New thing comes out, rocks the world, everyone says it's the next best thing since jQuery and will definitely make all your code better and all your knowledge obsolete. Time to learn stuff!

Untrue.

React hooks are neat. They look useful. They don't deprecate anything. Please don't rewrite your apps in hooks. Yet.

I watched Ryan's talk 90% cleaner with hooks last night, Dan's and Sophie's talk announcing hooks this morning, read all the docs, and watched Twitter like a disinterested hawk all weekend.

Hours of research condensed into the next 200 words because I love you. ❀️

Here's what you need to know about hooks right now πŸ‘‡

You can try them out.

  1. create-react-app look-ma-no-classes
  2. Open package.json, change react and react-dom to `next
  3. yarn install

Try out hooks

Hooks exist to rid your codebase of classes. Because classes are confusing to both people and compilers.

Where you used to class, you can now hook. In your functional components.

Built-in hooks cover the most common uses cases. You can build your own for everything else.

useState

The useState hook replaces pairs of state getters and setters.

class myComponent extends React.Component {
	state = {
	  value: 'default'
	}

	handleChange = (e) => this.setState({
	  value: e.target.value
	})

	render() {
	  const { value } = this.state;

	  return <input value={value} onChange={handleChange} />
	}
}

πŸ‘‡

const myComponent = () => {
  const [value, setValue] = useState('default');

  const handleChange = (e) => setValue(e.target.value)

  return <input value={value} onChange={handleChange} />
}

Less code to write and understand.

In a class component you:

  • set a default value
  • create an onChange callback that fires setState
  • read value from state before rendering etc.

Without modern fat arrow syntax you might run into trouble with binds.

The hook approach moves that boilerplate to React's plate. You call useState. It takes a default value and returns a getter and a setter.

You call that setter in your change handler.

Behind the scenes React subscribed your component to that change. Your component re-renders.

useEffect

useEffect replaces the componentDidMount, componentDidUpdate, shouldComponentUpdate, componentWillUnmount quadfecta. It's like a trifecta, but four.

Say you want a side-effect when your component updates, like make an API call. Gotta run it on mount and update. Want to subscribe to a DOM event? Gotta unsubscribe on unmount.

Wanna do all this only when certain props change? Gotta check for that.

Class:

class myComp extends Component {
  state = {
	  value: 'default'
	}

	handleChange = (e) => this.setState({
	  value: e.target.value
	})

	saveValue = () => fetch('/my/endpoint', {
		method: 'POST'
		body: this.state.value
	})

	componentDidMount() {
		this.saveValue();
	}

	componentDidUpdate(prevProps, prevState) {
		if (prevState.value !== this.state.value) {
			this.saveValue()
		}
	}

	render() {
	  const { value } = this.state;

	  return <input value={value} onChange={handleChange} />
	}
}

πŸ‘‡

const myComponent = () => {
  const [value, setValue] = useState('default');

  const handleChange = (e) => setValue(e.target.value)
  const saveValue = () => fetch('/my/endpoint', {
		method: 'POST'
		body: this.state.value
	})

	useEffect(saveValue, [value]);

  return <input value={value} onChange={handleChange} />
}

So much less code!

useEffect runs your function on componentDidMount and componentDidUpdate. And that second argument, the [value] part, tells it to run only when that value changes.

No need to double check with a conditional. If your effect updates the component itself through a state setter, the second argument acts as a shouldComponentUpdate of sorts.

When you return a method from useEffect, it acts as a componentWillUnmount. Listening to, say, your mouse position looks like this:

const [mouseX, setMouseX] = useState();
const handleMouse = (e) => setMouseX(e.screenX);

useEffect(() => {
	window.addEventListener('mousemove', handleMouse);
	return () => window.removeEventListener(handleMouse);
})

Neat πŸ‘Œ

Waiting for the day we can use this to do naughty DOM stuff in functional components. Limiting factor right now is that we can't have refs I think.

useContext

useContext cleans up your render prop callbacky hell.

<SomeContext>
  {state => ...}
</SomeContext>

πŸ‘‡

const state = useContext(SomeContext)

Context becomes just a value in your function. React auto subscribes you to all updates.

useReducer

useReducer is like React got Redux built in now. Whoa.

You don't really have to know this one. But it comes by default and it's kinda neat. Although I think using it for realz will lead to your components becoming way too big and bloated.

You should watch Ryan's talk to learn more about this one. Too long to explain in a nutshell πŸ₯ post.

[YT screenshot at this timestamp: https://youtu.be/wXLf18DsV-I?t=1538]

[link screenshot to link with previous timestamp above]

So?

Will hooks change the way you write React forever? We'll see. The internet is excited.

You can write your own hooks. Repositories of hooks are popping up like crazy. I'm sure your internet will be full of them for the next while.

Most importantly πŸ‘‡

  1. You can write your own hooks and re-use functionality between components. It's just a function.
  2. Dan and Sophie say this is the future of React. All functional. No classes.

GraphQL in a nutshell

GraphQL, the graph query language, is an amazing new way for clients and servers to communicate. No more REST APIs and building complex backends for every little thing.

Your backend exposes a single endpoint, your client asks for what it needs. GraphQL machinery handles the rest.

Imagine a world where you no longer have to think about different endpoints for different resources. A world where you don't have to build a new API for every type of data. A world where you often don't have to change anything at all to fetch some additional parameters you hadn't thought of before.

GraphQL is that world.

There's an endpoint that accepts your query, passes it through GraphQL machinery, does the things, and returns it back through GraphQL. That makes sure you only get the parameters you asked for.

It's wonderful. ❀️

Try it on my lambda here -> click

Reading

Mutating

GraphiQL

Apollo

TypeGraphQL

https://typegraphql.ml/

A great library you can use to unify your typescript and graphql types. We're going to skip it today so there's less new-ness in the workshop code. Instead we're going to write a little more boilerplate code and have some code repetition.

Repetition is okay when it gives you simplicity.

Serverless in a nutshell

AWS Lambda

DynamoDB

awslabs/dynamodb-data-mapper will give us an easier to use interface for DynamoDB than using the API directly. It's a minimalist ORM of sorts.

NodeJS