diff --git a/src/react-render-perf/README.md b/src/react-render-perf/README.md
new file mode 100644
index 0000000..0e2bbc8
--- /dev/null
+++ b/src/react-render-perf/README.md
@@ -0,0 +1,11 @@
+# React Render Perf
+
+The purpose of this workshop is to learn about common issues that can result
+react renders taking longer than expected.
+
+## Lessons
+
+1. Memoizing expensive to render components
+2. Prevent React.Context from re-render the whole tree
+3. Avoid using React.Context at all
+4. Minimizing re-renders by splitting up large components
diff --git a/src/react-render-perf/index.tsx b/src/react-render-perf/index.tsx
deleted file mode 100644
index b80fde1..0000000
--- a/src/react-render-perf/index.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import {Link} from "react-router-dom";
-
-export default function ReactRenderPerf() {
- return (
- <>
- Home
-
React Render Perf
-
-
- Example 1
-
-
- Example 2
-
-
- Example 3
-
-
- >
- );
-}
diff --git a/src/react-render-perf/lesson-01/README.md b/src/react-render-perf/lesson-01/README.md
new file mode 100644
index 0000000..e1a3d99
--- /dev/null
+++ b/src/react-render-perf/lesson-01/README.md
@@ -0,0 +1,129 @@
+# 01 - Memoizing Expensive Components
+
+Memoization can be used to avoid unnecessary renders. This is most useful when
+the component itself is expensive to render (e.g. the `MathJax` component in
+webapp) or it renders a lot of descedent components.
+
+Memoization works by saving the rendered output of the component based on the
+props that are being passed in. Often times props will appear to have changed
+when their actual values haven't. In JavaScript, two objects with the same
+properties are considered different objects. Similarly, two functions with the
+same implementation are considered differen objects.
+
+In order for memoization to have the desired benefit, we want don't want the
+component to rerender if there are only superficial changes to props.
+
+`React.memo(Component, arePropsEqual?)` by default does a shallow comparison of
+props and as such isn't able to determine when a prop that's on object or function
+is the same or not. We can pass a custom `arePropsEqual` function to override
+that behavior. To keep things simple we use a third-party library called
+`react-fast-compare` which provides a function that does a deep comparison of
+objects.
+
+```ts
+import arePropsEqual from "react-fast-compare";
+
+type Props = {
+ user: {name: string, id: string},
+ onClick: () => void,
+}
+
+const ChildComponent = (props: Props) => {
+ // ...
+}
+
+export default React.memo(ChildComponent, arePropsEqual);
+```
+
+There is a bit of a gotcha here when it comes to props that are functions.
+`react-fast-compare` cannot check if two functions are the same. Imagine the
+following scenario:
+
+```ts
+import ChildComponent from "./child-component";
+
+type Props = {
+ user: {name: string, id: string},
+};
+
+const ParentComponent = (props: Props) => {
+ const result = useQuery(QUERY);
+
+ const handleClick = () => {
+ if (result.data) {
+ // do something with the data
+ }
+ };
+
+ return
+}
+```
+
+Each time `ParentComponent` renders, a new copy of `handleClick` will be created
+even if the `result` from `useQuery` isn't ready yet. We only want this function
+to treated as a new function when `result` changes. React provides a hook called
+`useCallback` which does exactly that by memoizing the function.
+
+```ts
+import ChildComponent from "./my-component";
+
+type Props = {
+ user: {name: string, id: string},
+};
+
+const ParentComponent = (props: Props) => {
+ const result = useQuery(QUERY);
+
+ const handleClick = React.useCallback(() => {
+ if (result.data) {
+ // do something with the data
+ }
+ }, [result]);
+
+ return
+}
+```
+
+If the `ParentComponent` is a class-based component, there is no need to memoize
+function props that are pre-bound methods. This is because the method never changes
+for the component instance. If the prop is an inline function though, it should be
+convered to a pre-bound method.
+
+```ts
+import ChildComponent from "./my-component";
+
+type Props = {
+ user: {name: string, id: string},
+};
+type State = {
+ result?: Result,
+}
+
+class ParentComponent extends React.Component {
+ componentDidMount() {
+ fetch(QUERY).then((result) => {
+ this.setState({result});
+ });
+ }
+
+ handleClick = () => {
+ if (this.result?.data) {
+ // do something with the data
+ }
+ }
+
+ render() {
+ return
+ }
+}
+```
+
+**WARNING:**
+Memoization is not free. It requires memory so you should be picky when deciding
+what to memoize.
+
+| Good Candidates | Bad Candidates |
+| ------------------------------------------ | ---------------------------------------- |
+| lots of descendants | few descendants |
+| expensive to render | inexpensive to render |
+| actual values of props change infrequently | actual values of props change frequently |
diff --git a/src/react-render-perf/lesson-01/exercise.tsx b/src/react-render-perf/lesson-01/exercise.tsx
new file mode 100644
index 0000000..6d31df1
--- /dev/null
+++ b/src/react-render-perf/lesson-01/exercise.tsx
@@ -0,0 +1,3 @@
+export default function Exercise1() {
+ return
Exercise 1: Memoizing Expensive Components
;
+}
diff --git a/src/react-render-perf/lesson-02/README.md b/src/react-render-perf/lesson-02/README.md
new file mode 100644
index 0000000..2179bf9
--- /dev/null
+++ b/src/react-render-perf/lesson-02/README.md
@@ -0,0 +1,3 @@
+# 02 - Prevent Context From Rerendering
+
+TODO
diff --git a/src/react-render-perf/lesson-02/exercise.tsx b/src/react-render-perf/lesson-02/exercise.tsx
new file mode 100644
index 0000000..768efba
--- /dev/null
+++ b/src/react-render-perf/lesson-02/exercise.tsx
@@ -0,0 +1,3 @@
+export default function Exercise2() {
+ return
Exercise 2: Prevent Context From Rendering
;
+}
diff --git a/src/react-render-perf/lesson-03/README.md b/src/react-render-perf/lesson-03/README.md
new file mode 100644
index 0000000..9225467
--- /dev/null
+++ b/src/react-render-perf/lesson-03/README.md
@@ -0,0 +1,3 @@
+# 03 - Avoid Using Context
+
+TODO
diff --git a/src/react-render-perf/lesson-03/exercise.tsx b/src/react-render-perf/lesson-03/exercise.tsx
new file mode 100644
index 0000000..dcf471b
--- /dev/null
+++ b/src/react-render-perf/lesson-03/exercise.tsx
@@ -0,0 +1,3 @@
+export default function Exercise3() {
+ return
Exercise 3: Avoid Using Context
;
+}
diff --git a/src/react-render-perf/lesson-04/README.md b/src/react-render-perf/lesson-04/README.md
new file mode 100644
index 0000000..5149ef5
--- /dev/null
+++ b/src/react-render-perf/lesson-04/README.md
@@ -0,0 +1,3 @@
+# 04 - Splitting Large Components
+
+TODO
diff --git a/src/react-render-perf/lesson-04/exercise.tsx b/src/react-render-perf/lesson-04/exercise.tsx
new file mode 100644
index 0000000..6759433
--- /dev/null
+++ b/src/react-render-perf/lesson-04/exercise.tsx
@@ -0,0 +1,3 @@
+export default function Exercise4() {
+ return
Exercise 4: Splitting up large components
;
+}
diff --git a/src/react-render-perf/routes.tsx b/src/react-render-perf/routes.tsx
new file mode 100644
index 0000000..7084024
--- /dev/null
+++ b/src/react-render-perf/routes.tsx
@@ -0,0 +1,29 @@
+import {BrowserRouter, Route} from "react-router-dom";
+
+import TableOfContents from "./table-of-contents";
+import Lesson1Exercise from "./lesson-01/exercise";
+import Lesson2Exercise from "./lesson-02/exercise";
+import Lesson3Exercise from "./lesson-03/exercise";
+import Lesson4Exercise from "./lesson-04/exercise";
+
+export default function Routes() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/react-render-perf/table-of-contents.tsx b/src/react-render-perf/table-of-contents.tsx
new file mode 100644
index 0000000..74d1bcd
--- /dev/null
+++ b/src/react-render-perf/table-of-contents.tsx
@@ -0,0 +1,32 @@
+import {Link} from "react-router-dom";
+
+export default function ReactRenderPerf() {
+ return (
+ <>
+ Home
+
React Render Perf
+
+
+
+ 01 - Memoizing Expensive Components
+
+
+
+
+ 02 - Prevent Context From Rendering
+
+
+
+
+ 03 - Avoid Using Context
+
+
+
+
+ 04 - Splitting Up Large Components
+
+
+
+ >
+ );
+}
diff --git a/src/routes.tsx b/src/routes.tsx
index 53ff88c..72ad9ae 100644
--- a/src/routes.tsx
+++ b/src/routes.tsx
@@ -1,6 +1,6 @@
import {BrowserRouter, Route} from "react-router-dom";
-import ReactRenderPerf from "./react-render-perf";
+import ReactRenderPerfRoutes from "./react-render-perf/routes";
import Homepage from "./homepage";
export default function Routes() {
@@ -9,8 +9,8 @@ export default function Routes() {
-
-
+
+
);