diff --git a/pitfalls.md b/pitfalls.md
index f7f71e8..2f7888a 100644
--- a/pitfalls.md
+++ b/pitfalls.md
@@ -1,6 +1,20 @@
-# WebGL performance pitfalls ☠️
+# Performance pitfalls
-This is the best overview i could find: https://discoverthreejs.com/tips-and-tricks
+## Table of Contents
+1. [WebGL performance pitfalls](#webgl-pitfalls)
+ 1. [Tips and Tricks](#-tips-and-tricks)
+2. [React performance pitfalls](#react-pitfalls)
+ 1. [Never, ever, setState animations](#never-ever-set-state)
+ 2. [Never let React anywhere near animated updates](#never-let-react-animate)
+ 3. [Never bind often occuring reactive state to a component](#never-bind-reactive-component)
+ 4. [Do not mount/unmount things indiscriminately](#do-not-mount-unmount-indiscriminately)
+
+
+## WebGL performance pitfalls ☠️
+
+### Tips and Tricks
+
+This is the best overview I could find: https://discoverthreejs.com/tips-and-tricks
The most important is, creating objects in Threejs is expensive, think twice before you mount/unmnount things, because every material that you put into the scene has to compile, every geometry you create will be processed. Share materials and geometries if you can, either in global scope or locally:
@@ -12,9 +26,9 @@ return items.map(i =>
-❌ **Never, ever, setState animations:**
+### ❌ Never, ever, setState animations!
```jsx
const [x, setX] = useState(0)
@@ -26,7 +40,7 @@ return
You are forcing a full component (+ its children) through React and its diffing mechanism 60 times per second.
-✅ Instead, use refs and mutate! This is totally fine and that's how you would do it in plain Threejs as well.
+#### ✅ Instead, use refs and mutate! This is totally fine and that's how you would do it in plain Threejs as well.
```jsx
const ref = useRef()
@@ -34,11 +48,11 @@ useFrame(() => ref.current.position.x += 0.01)
return
```
-❌ **Never let React anywhere near animated updates!**
+### ❌ Never let React anywhere near animated updates!
Instead use animation libs that animate outside of React! Avoid libs like react-motion that re-render the component 60fps!
-✅ Using [lerp](https://github.com/mattdesl/lerp) + useFrame:
+#### ✅ Using [lerp](https://github.com/mattdesl/lerp) + useFrame:
```jsx
import lerp from 'lerp'
@@ -49,7 +63,7 @@ function Signal({ active }) {
return
```
-✅ Or [react-spring](https://github.com/react-spring/react-spring), which animates outside of React:
+#### ✅ Or [react-spring](https://github.com/react-spring/react-spring), which animates outside of React:
```jsx
import { a, useSpring } from 'react-spring/three'
@@ -59,7 +73,7 @@ function Signal({ active }) {
return
```
-❌ **Never bind often occuring reactive state to a component**
+### ❌ Never bind often occuring reactive state to a component!
Using state-managers and selected state is fine, but not for updates that happen rapidly!
@@ -71,14 +85,14 @@ const x = useSelector(state => state.x)
return
```
-✅ Fetch state directly, for instance using [zustand](https://github.com/react-spring/zustand):
+#### ✅ Fetch state directly, for instance using [zustand](https://github.com/react-spring/zustand):
```jsx
useFrame(() => ref.current.position.x = api.getState().x)
return
```
-✅ Or, subscribe to your state [in a way that doesn't re-render](https://github.com/react-spring/zustand#transient-updates-for-often-occuring-state-changes) the component:
+#### ✅ Or, subscribe to your state [in a way that doesn't re-render](https://github.com/react-spring/zustand#transient-updates-for-often-occuring-state-changes) the component:
```jsx
const ref = useRef()
@@ -86,11 +100,11 @@ useEffect(() => api.subscribe(x => ref.current.position.x = x, state => state.x)
return
```
-❌ **Do not mount/unmount things indiscriminately**
+### ❌ Do not mount/unmount things indiscriminately!
In Threejs it is very common to not re-mount at all, see the ["disposing of things"](https://discoverthreejs.com/tips-and-tricks/) section in discover-three. This is because materials get re-compiled, etc.
-✅ Use concurrent mode:
+#### ✅ Use concurrent mode:
Switch React to `@experimental` and flag the canvas as concurrent. Now React will schedule and defer expensive operations. You don't need to do anything else, but you can play around with the [experimental scheduler](https://github.com/drcmda/scheduler-test) and see if marking ops with a lesser priority makes a difference.