Skip to content

Commit

Permalink
Merge to trunk
Browse files Browse the repository at this point in the history
Resolve merge conflict in index.css
  • Loading branch information
JDSeiler committed Nov 22, 2024
3 parents e6b9d98 + 77a77f8 + 295509f commit b1cfe08
Show file tree
Hide file tree
Showing 3 changed files with 523 additions and 2 deletions.
34 changes: 32 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,32 @@
# Page Header
Hello 11ty!
# Webpage
Source repository for my personal site / blog, written using https://www.11ty.dev/.

## Project Config
Here's some notes on how this whole thing is wired up, for my own sanity when I
go to make changes and it's been 6 months.

- `npm run build` :: Makes the "production" build
- `npm run serve` :: Starts a hot-reloading local dev server
- `npm run spell:posts` :: Spell-checks the posts directory
- `npm run spell:all` :: Spell-checks the whole repo

Publishing is done with the `build-publish` GitHub action, and happens on merge to `trunk`.

eleventy is configured to copy the `src/css`, `src/img` directories, as well as the
`CNAME` file into the built site. This means they can be directly referenced through
absolute paths like `/css/index.css`.

All of the CSS for the whole site is implemented in one big file. The only thing that's
split out is the Prism theme used for syntax highlighting.

## Setup and Usage

Make sure you're using at *least* Node 18.

1. `npm install`
2. `npm run serve`
3. Write a new blog post in markdown
4. Spell check, proofread, and edit
5. Through some means, push to trunk
a. Direct push?
b. Push a branch and merge in GitHub?
103 changes: 103 additions & 0 deletions drafts/react-effects.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Manage Effects Carefully
[You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect)
might be the single greatest piece of documentation released for React. I think every
React developer should read it and re-read it regularly. Now, I don't want to regurgitate
that documentation, just go read the original. But, I do want to highlight one particular
anti-pattern with effects that I see *all the time*, which is using them to compute values
based on props or state:
```tsx
const NeutrinoEngineCarborator = () => {
const [overdrive, setOverdrive] = useState(false);

useEffect(() => {
if (window.location.search.includes("overdrive=1")) {
setOverdrive(true);
}
}, []);

// blah blah blah
}
```

In this example, we can calculate `overdrive` directly in rendering, removing the effect
and state:
```tsx
const NeutrinoEngineCarborator = () => {
const overdrive = window.location.search.includes("overdrive=1");

// blah blah blah
}
```
Or, consider this example. We're writing the dashboard for a spaceship. We're provided
with a list of engine subsystems, and a list of the same subsystems ranked by how in
danger they are of exploding ("peril"). We want to highlight the most in-danger
subsystem in our dashboard. we might write the code something like the following.
If you think my example code isn't realistic, know that it's based off code I have
seen out in the wild, obviously with superficial details changed to protect the innocent.
```tsx
// The types aren't that important
type SubSys = {
id: string;
name: string;
// You can use your imagination for other props
}

type Peril = {
id: string; // system in peril
rating: number // higher === more peril
}

const WarpDriveSubsystemManager = () => {
// All subsystems
const subsystems: SubSys[] = useSelector(selectSubsystems);
// List of subsystems that are failing
const systemsInPeril: Peril[] = useSelector(selectPeril);
const [
prioritySys,
setPrioritySys
] = useState<SubSys | null>(null);

useEffect(() => {
// You can use your imagination for how
// findMaxPeril is implemented
const { id: mostPerilous } = findMaxPeril(systemsInPeril);
const mostInPeril = subsystems.find(s => s.id === mostPerilous);
setPrioritySys(mostInPeril);
}, [subsystems, systemsInPeril]);

// blah blah blah
}
```
This code has some soundness issues unrelated to effects, like what happens where there
are no systems in peril, but that's not the point. Let's see how we can simplify this
code, warts and all:
```tsx
const getMaxPeril = (subsystems: SubSys[], systemsInPeril: Peril[]): SubSys => {
const { id: mostPerilous } = findMaxPeril(systemsInPeril);
const mostInPeril = subsystems.find(s => s.id === mostPerilous);
return mostInPeril;
};

const WarpDriveSubsystemManager = () => {
// All subsystems
const subsystems: SubSys[] = useSelector(selectSubsystems);
// List of subsystems that are failing
const systemsInPeril: Peril[] = useSelector(selectPeril);
const prioritySys = getMaxPeril(subsystems, systemsInPeril);

// blah blah blah
}
```
Why is using an effect in this way bad? It's because effects run *after* React renders your
components and commits them to the DOM. So, if an effect immediately sets state, it's going
to trigger an entirely new render cycle. Not only is this inefficient, it also results in
code that is unecessarily complex.

In both examples, removing the effect and state makes the code easier to read and understand,
more performant, and shorter.

Some might quibble that performing the computations (`getMaxPeril` and
`window.location.search.includes`) every render could cause performance issues. But, if you find
a component is slow and *run a benchmark* to prove that an in-render computation is the
bottleneck, you should reach for [useMemo](https://react.dev/reference/react/useMemo) and **not**
`useEffect`.
Loading

0 comments on commit b1cfe08

Please sign in to comment.