Chris Padilla/Blog
My passion project! Posts spanning music, art, software, books, and more. Equal parts journal, sketchbook, mixtape, dev diary, and commonplace book.
- Improved line quality
- Comfort with failure
- Intuitive perspective
- Spacial reasoning
- Balancing play with study
- Persistence for a craft that's not easy to pick up
- Background
- Borders
- Colors
- Display
- Opacity
- Position
- Sizing
- Vertical Align
- Z-Index
- Data Caching
- Refetching at an interval
- Data Fetching State (such as
isLoading
orerror
)
NVM, Next 13, and the "Latest" Package Version, OH MY!
I received notice from Vercel, the host of this very website, that Node 14 and 16 were being deprecated. This very website was developed with a local version of Node 12! š±
I didn't anticipate any breaking changes with Node, I'm not using edge case functions here for this website, but I wanted to do my due diligence for Vercel.
What started as a harmless updated nearly ended in a nightmare for me. Come along as I regale the tale of NVM, Next 13, and npm package versions!
NVM
Node Version Manager is exactly that ā a utility for loading multiple versions of Node on your machine and switching between them. I'm already using multiple versions of Python, so I decided it was time to give NVM a whirl.
Installation was pretty straight forward following Digital Ocean's guide.
So the switch is made: Node 12 updated to version 18.
NPM
On to testing my site locally with npm run dev
. Doing so alerted me to a few conflicting dependencies, which was a surprise. Seems nvm also manages npm versions as well, which is great! This new version was catching potential issues in my packages. The conflict was mainly between react testing library and react.
Easy enough, I adjusted the version numbers and ran npm i
Next Version 13
Suddenly, surprise!! My starter project that this is based on left this in the package.json
:
"dependencies": {
"next": "latest",
},
I've never seen that before, and with good reason. Latest will upgrade the major version when available, bringing breaking changes along with it! Suddenly, my Next <Image />
elements weren't sizing correctly, and my <Link />
tags were deprecated.
All fine and well if this were a production site I had ample time to maintain. But, that, this is not.
Long story short ā a dive into trying to upgrade to version 13 ultimately ended with me setting my next version to "^12.0.0"
for simplicity's sake.
Deployed Build
Surprisingly, I only ran into this issue locally. It lead me to wonder why I wasn't seeing the same errors from Next 13 on the live site.
I thought that it might be because the Next version is set through the CLI or on Vercel, but neither are true.
It seems that it's likely actually dependent on the node version. Here's Vercel's upgrading guide on the matter:
The minimum Node.js version has been bumped from 12.22.0 to 14.18.0, since 12.x has reached end-of-life.
The minimum React version has been bumped from 17.0.2 to 18.2.0.
I'm just shy on both of those, so I imagine there were some checks that fell back to a previous version of Next in those cases.
Moral of the story: beware of "Latest" versions in your package.json files!
Faber - Chocolate Blues
I Drew 250 Boxes for Drawabox. Should you?
Yes.
I've written about the infamous 250 box challenge over at Drawabox. I've admittedly started and forfeited the challenge a couple of times. I resisted the 50% rule at my own peril.
And I'm here to say I'm so glad I went back in and saw it to completion.
The challenge is outlined on their site, but for anyone unfamiliar, the gist is to draw boxes. In three point perspective. In ink. And extend your edges to their vanishing points.
It's a bit gnarly, which is why Uncomfortable and the community around the site are very adamant about the 50% percent rule. Even if you don't learn any technique, I think the 50% rule of balancing study with play is a fantastic lesson to carry into any practice, art or otherwise.
It's tempting to assume the reward of completing it is simply to really nail boxes. But here's what all you learn along the way:
Best yet, these all culminate in the following lessons on drawing bugs and animals. Those lessons are where things really started to click for me as far as seeing every drawing as a combination of shapes that can be manipulated in 3D space. Even if the ultimate goal is a flat, 2D image, an understanding of 3D underneath all that makes it all the easier to play with those shapes.
I've looked at a few different avenues for getting started with drawing: Proko, Andrew Loomis, Preston Blair. I'd say, though, drawabox is where I'd recommend someone brand new start out. The material can be dense, but uncomfortable does an amazing job of starting right away with the meat of what you really need to invent with your drawings.
At this point, I'm up to the cylinder challenge, getting ready to start lesson 6 ā Drawing Everyday objects. I think most folks will get the most mileage out of completing up to about where I am, but I'm excited to see how this last leg of the course builds.
These ROCK
Migrating a React App To TypeScript
After 10 years on the scene, TypeScript has become an essential tool in many codebases.
The benefits are primarily static testing: Similar to C#, you'll get compile time errors regarding type-mismatches.
Though, most folks I know that use it love it for the DX. VS Code has first class support for TypeScript, providing stellar autocomplete for all objects and classes that are typed in your codebase. Likely, you've already enjoyed the benefits of autocomplete for methods from external libraries that ship with Types.
Migrating Create React App to TypeScript
There was a time when getting the tooling for TypeScript up and running was a headache. Not anymore! Many modern frameworks can initialize a project with TypeScript using a simple options flag in the CLI.
If working with Create React App, migrating is wildly easy. Simply install typescript dependencies, then restart your dev server.
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
Opt In
It's easy to dip your toes into TypeScript because it's an opt in system. The same TypeScript project can have as many JS files in your /src.
So to get started, simply convert a file.js
to file.tsx
for react and you're off and running!
A note here: your bundler may support JS imports without the file name, but you may need to be explicit with TypeScript imports.
// JS File
import EditAuthors from './components/EditAuthors';
// TSX Files, will not compile without file extension
import EditBook from './components/EditBook.tsx';
import Books from './components/Books.tsx';
import Book from './components/Book.tsx';
Package Types
Again ā there was a time where not all packages shipped with Types. Long gone are those days now! When using an external library, you should be able to find info in their documentation about supported types. Here's Formik as an example.
import { Formik, FormikErrors } from 'formik';
import { BookSubmitObject } from '../types';
<Formik
initialValues={initialValues}
validate={(values: BookSubmitObject) => {
const errors: FormikErrors<BookSubmitObject> = {};
// Validate Errors
if (values.rating > 5 || values.rating < 1) {
errors.rating = 'Must be within 1 and 5';
}
return errors;
}}
...
>
So that's getting setup! More on how to actually write with TypeScript another time. š
Picking a Locale ā Overcoming the Blank Page with Carl Barks
A fun rabbit hole I've been down is learning more about "The Good Duck Artist" Carl Barks.
Barks was a self taught cartoonist and an early legend in comics. He's known for his Donald Duck and Scrooge McDuck cartoons. Wickedly talented in every domain within comics ā Story, drawing, expression, color, inking ā he was also incredibly prolific, releasing comics regularly over a 25 year career.
Interestingly enough, Barks was more widely famous in Danish culture as opposed to the US due to Donald Duck being the lead character in Denmark instead of Mickey Mouse. Hence, why one of my top searches for "Carl Barks Interviews" brought me to a Danish recording:
Aside from how lighthearted Barks is about his work and characters, my favorite part of the interview comes from the question of how he came up with all of these stories:
"I would just start thinking of what I would like to draw. Because those comic book stories required a great number of hours of drawing and if I could think of some pleasant place ā a south sea island or trip into the mountains ā something that would give me some good backgrounds and interesting things to draw, then I would chose that as the locale of my store. Then once I've chosen the locale... somehow the ideas for a story, something for those ducks to do, would just come about! The ideas would just pour down onto my head."
I've heard elsewhere that Barks would use National Geographic issues as reference and inspiration for these far-flung adventures.
From his Biography, Terry Pratchett described in his process having a horizon off in the distance. He didn't always know how he was going to hit certain story beats, but having a destination helped move the story there.
My biggest case of "fearing the blank page" comes with writing music. Something about music being less physical makes it a bit more daunting to get started on. But stories really aren't so different. Nothing helps me kick start a song quicker than deciding on a "locale" ā be it genre, a pallet of instruments, or even just a song title.
As is my contractual obligation to say in these posts: So it is with anything creative. Starting with a title helps with writing. Starting with a subject matter helps with drawing. Starting with an app idea helps with software.
Starting an adventure is easier once you've settled on a point of departure.
Spanish Melody
Picked up a new book for this pretty instrument.
Moose!
Utility Classes in Bootstrap
TIL that Bootstrap has a few utility classes for customizing beyond the basic styles.
This was a surprise to me! My experiences with Bootstrap has been to quickly put together prototypes and learning projects. So custom templating was not a high priority. Whatever came out of the box worked fine.
Though, in my current case, I had a situation where I wanted to adjust spacing. In Tailwind or a CSS-in-JS environment, granular updates are easy enough. But in my current project, I've only been using bootstrap styles. So I was looking at a potential break in flow if I reached for another css library or fired up a css file just for a few custom spacing classes.
Not the end of the world to go with those options, but it's handy to see that Bootstrap had me covered!
If you're familiar with Tailwind, these will look pretty familiar. Here's the example from Bootstrap's docs:
.mt-0 {
margin-top: 0 !important;
}
.ms-1 {
margin-left: ($spacer * .25) !important;
}
.px-2 {
padding-left: ($spacer * .5) !important;
padding-right: ($spacer * .5) !important;
}
.p-3 {
padding: $spacer !important;
}
Actually, looking through the Utilities sections of the docs, there are several utility classes that I commonly reach for in tailwind:
It doesn't cover the whole spectrum of CSS in the same way that Tailwind does, of course. Off the top of my head, I know that CSS transition properties are missing. Really, though, Tailwind is solving a different problem ā atomic classes to reduce premature abstraction while still keeping a highly flexible design system, whereas Bootstrap is a CSS framework.
I've largely stayed away from CSS frameworks in my personal projects. I'm comfortable with writing custom CSS, and I like the flexibility of writing by hand. I've been delightfully surprised with using Bootstrap lately, though. You could supplement any CSS library with utility classes through Tailwind or combine with custom CSS.
But, in cases where I want an all in one solution, I'll be keeping an eye out for libraries that expose their own utility classes.
My Comfort Work and "Do You Like Sentences?"
Technique is a bit of a vice for me.
When in doubt, I draw boxes.
When in doubt, I play scales.
When in doubt, I mess around with a toy app in software.
It's my vice because I'm guilty of probably practicing too much technique and not just making things more often. But there it is. It's my "comfort work" as Austin Kleon puts it.
To each their own. It gets me in the studio, in front of the piano, and in my code editor. Usually, that's where I need to start to get to the really good stuff, anyway.
I'm at least in good company. In The Writing Life, Annie Dillard shares an interaction between a fellow authorand a student where the student asks "Do you think I could be a writer?" Their response:
"Do you like sentences?"
I like sound and lines. I even like the colored text in VS Code! So I'll take it as a sign that I'm in all the right crafts.
Liszt ā Liebestraum No 3 (arranged)
A Good Pup
Data Fetching with React / TanStack Query
TanStack Query (formerly React Query) is a delightful library for handling state around fetching data. If you're familiar with Apollo Client for GraphQL, but aren't using GraphQL in your app, TanStack Query gives you many of the same benefits:
If you're coming from a redux environment, much of the above was managed by hand. TanStack Query, however, takes care of the above automatically, while still exposing opportunities to make manual fetches when needed.
Set Up
The quick start in the official docs should be enough to get you going.
The gist is you'll wrap your app in a QueryClient provider. Similar to the Redux provider, this will store your data at an application level.
import React, { Component } from 'react';
import { Route, Routes } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import AppRoutes from './AppRoutes';
import { Layout } from './components/Layout';
import './custom.css';
const App = () => {
const queryClient = new QueryClient();
return (
<QueryClientProvider client={queryClient}>
<Layout>
<Routes>
{AppRoutes.map((route, index) => {
const { element, ...rest } = route;
return <Route key={index} {...rest} element={element} />;
})}
</Routes>
</Layout>
</QueryClientProvider>
);
};
export default App;
Sending a Query
TanStack Query is not a replacement for fetch
. Its focus is the state and caching of your data. So you'll still need to write a query function:
const fetchBooks = async () => {
const response = await fetch('book');
const data = await response.json();
return data;
};
Once you have it, you'll pass it into the useQuery
hook with a couple of options:
const { data, isLoading } = useQuery({
queryKey: ['books'],
queryFn: fetchBooks,
});
The queryKey
is an array of values that will help keep your query labeled. This is helpful in the event you want to invalidate the query, essentially asking for another network request to be sent to update the data in the cache.
From the result, we're destructuring what we need: the data
and the state isLoading
.
isLoading
can be used to show a loader to the user in your UI:
return (
<div>
<h1 id="tableLabel">Books</h1>
<p>This page demonstrates fetching data from the server.</p>
<div>
{isLoading ? (
<p>
<em>Loading...</em>
</p>
) : (
renderTable(data)
)}
</div>
</div>
);
isLoading
pertains to the initial fetch. For the state of another query being sent, you'll want to reach for isFetching
.
Query With Filters
Sometimes you just need one book. Query keys are commonly used for passing arguments to your fetch methods.
Here's the useQuery
setup:
const { data, isLoading } = useQuery({
queryKey: ['books', { id }],
queryFn: fetchBook,
});
And here's how we access the arguments in the query function:
const fetchBook = async ({ queryKey }) => {
const [, { id }] = queryKey;
const response = await fetch(`book/edit/${id}`);
const data = await response.json();
return data;
};
Service and Expression
One of the best distinctions I made a few years ago was understanding that my work would be balanced by two spheres: Service and expression.
I dipped my toes into SVSLearn's illustration podcast on an episode about what it's like diving into the comics industry. Not my personal goal, but I've been reading a lot of comics and I thought it would be interesting!
Right out the gate, the guest described his work as a rollercoaster ride between the stable, steady work in animation and writing comics, where there's comparatively no money to be made.
Tim Ferris describes a similar back and forth in the Four Hour Work Week, coining the term"mini retirements." Tim would work his butt off launching a product or project, working 12-16 hour days, and then spending those same 12-16 hours in brazil learning salsa dancing for three months.
A little extreme for my personal taste and for this phase of life. To each their own, but in my experience it's a lot more sustainable to work a bit of both into your daily life.
Back to the podcast: the guest describes a tension creative people fill: to have the stability and camaraderie of working on a team to bring someone else's vision to life ā and the tension to create something wholly your own, and have your own voice fully expressed.
I think we all experience a bit of that, and we all find our own ways to fill those needs. Understanding that there's a difference between the purpose of those two spheres of work makes a world of a difference, though.
My software work isn't dragged down by ego. Because I have a few options for expression and play, I can more fully do work during the day that best serves the interest of my colleagues.
And vic versa. When I was a music teacher, my creative work felt like it had to be tied with teaching. I didn't feel like I could really explore visual art or piano or writing music because my full time gig was playing and teaching saxophone. Surely I had to be putting my free time in on the horn, too! Now, because my daytime work is a world apart, there's no baggage around what I should be doing to express myself. Heck, I've said it before, I'll say it again ā blogging has surprisingly been one of the best ways to fulfill that itch!
Calling those halves service and expression works for me, but maybe Tony Robin's terms of Stability and Instability works better for you. Or maybe Brene Brown's guidepost to find "Meaningful Work." I'm a person that's driven primarily by the desire to create. But say that you are actually primarily service driven. Then, the two spheres might include stable service and unstable service. That stable service of holding a marketing job that pays the bills, balanced with the unstable (but more fulfilling) service work of non-profit contributions and volunteering.
What ever the words really are ā finding balance between two complimentary needs can make the world of a difference in everyday fulfillment.