Skip to content

Commit 39a6ac0

Browse files
committed
docs: patterns & anti patterns
1 parent ed98822 commit 39a6ac0

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

docs/_guide/anti-patterns.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
chapter: 8
3+
subtitle: Anti Patterns
4+
---

docs/_guide/patterns.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
chapter: 7
3+
subtitle: Patterns
4+
---
5+
6+
An aim of Catalyst is to be as light weight as possible, and so we often avoid including helper functions for otherwise fine code. We also want to keep Catalyst focussed, and so where some helper functions might be reasonable, we recommend judicious use of other small libraries.
7+
8+
Here are a few common patterns which we've avoided introducing into the Catalyst code base, and instead encourage you to take the example code and run with that:
9+
10+
11+
### Debouncing or Throttling events
12+
13+
Often times you'll want to do something computationally intensive (or network intensive) based on a user event. It's worth throttling the amount of times a function can be called for these events, to prevent saturation of the CPU or network. For this we can use the "debounce" or "throttle" patterns. We recommend using the [`@github/mini-throttle`](https://github.com/github/mini-throttle) library for this, which provides convenient decorators to put on methods which will add throttling to them:
14+
15+
```typescript
16+
import {controller} from '@github/catalyst'
17+
import {debounce} from '@github/mini-throttle/decorators'
18+
19+
@controller
20+
class FuzzySearchElement extends HTMLElement {
21+
22+
// Adding `@debounce(100)` here means this method will only be called once in a 100ms period.
23+
@debounce(100)
24+
search(event: Event) {
25+
const value = event.currentTarget.value
26+
// This function is very computationally intensive, so we should run it as little as possible
27+
this.filterAllItemsWithValue(value)
28+
}
29+
30+
}
31+
```
32+
33+
### Aborting Network Requests
34+
35+
When making network requests using `fetch`, based on user input, you can cancel old requests as new ones come in, this is useful for performance as well as UI responsiveness, as old requests that aren't cancelled might complete later than newer ones causing the UI to jump around. Aborting network requests requires you to use [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) (a web platform feature).
36+
37+
```typescript
38+
@controller
39+
class RemoveSearchElement extends HTMLElement {
40+
41+
#remoteSearchController: AbortController|null
42+
43+
async search(event: Event) {
44+
// Abort the old Request
45+
this.#remoteSearchController?.abort()
46+
47+
// To start making a new request, construct an AbortController
48+
const {signal} = (this.#remoteSearchController = new AbortController())
49+
50+
try {
51+
const res = await fetch(myUrl, {signal})
52+
53+
// ... Add logic here with the completed network response
54+
} catch (e) {
55+
56+
// ... Add logic here if you need to report a failed network request.
57+
// Do not rethrow for network errors!
58+
59+
}
60+
61+
if (signal.aborted) {
62+
// Here you can add logic for if the request was cancelled, but
63+
// usually what you want to do is just return early to avoid
64+
// cleaning up the loading UI (bear in mind if the request is
65+
// cancelled then another one will be in its place).
66+
return
67+
}
68+
69+
// ... Add cleanup logic here, such as removing `loading` classes.
70+
71+
}
72+
}
73+
```

0 commit comments

Comments
 (0)