From 6df03db987ab5d048985f078812c1ec5a73c6c1f Mon Sep 17 00:00:00 2001 From: "Kent C. Dodds" Date: Fri, 8 Mar 2024 15:47:50 -0700 Subject: [PATCH] 06 done --- .../05.portals/01.problem.create/tooltip.tsx | 1 - .../05.portals/01.solution.create/tooltip.tsx | 1 - .../01.problem.layout-effect/README.mdx | 27 +++++++++++++++++++ .../01.problem.layout-effect}/form.tsx | 0 .../01.problem.layout-effect}/index.css | 0 .../01.problem.layout-effect}/index.tsx | 0 .../01.problem.layout-effect}/params.tsx | 0 .../01.problem.layout-effect}/posts.tsx | 0 .../01.problem.layout-effect}/tooltip.tsx | 2 ++ .../01.solution.layout-effect/README.mdx | 13 +++++++++ .../01.solution.layout-effect}/form.tsx | 0 .../01.solution.layout-effect}/index.css | 0 .../01.solution.layout-effect}/index.tsx | 0 .../01.solution.layout-effect}/params.tsx | 0 .../01.solution.layout-effect}/posts.tsx | 0 .../01.solution.layout-effect}/tooltip.tsx | 0 exercises/06.layout-computation/FINISHED.mdx | 3 +++ exercises/06.layout-computation/README.mdx | 26 ++++++++++++++++++ .../06.layout-effect/01.problem/README.mdx | 1 - .../06.layout-effect/01.solution/README.mdx | 1 - exercises/06.layout-effect/FINISHED.mdx | 0 exercises/06.layout-effect/README.mdx | 3 --- 22 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 exercises/06.layout-computation/01.problem.layout-effect/README.mdx rename exercises/{06.layout-effect/01.problem => 06.layout-computation/01.problem.layout-effect}/form.tsx (100%) rename exercises/{06.layout-effect/01.problem => 06.layout-computation/01.problem.layout-effect}/index.css (100%) rename exercises/{06.layout-effect/01.problem => 06.layout-computation/01.problem.layout-effect}/index.tsx (100%) rename exercises/{06.layout-effect/01.problem => 06.layout-computation/01.problem.layout-effect}/params.tsx (100%) rename exercises/{06.layout-effect/01.problem => 06.layout-computation/01.problem.layout-effect}/posts.tsx (100%) rename exercises/{06.layout-effect/01.problem => 06.layout-computation/01.problem.layout-effect}/tooltip.tsx (93%) create mode 100644 exercises/06.layout-computation/01.solution.layout-effect/README.mdx rename exercises/{06.layout-effect/01.solution => 06.layout-computation/01.solution.layout-effect}/form.tsx (100%) rename exercises/{06.layout-effect/01.solution => 06.layout-computation/01.solution.layout-effect}/index.css (100%) rename exercises/{06.layout-effect/01.solution => 06.layout-computation/01.solution.layout-effect}/index.tsx (100%) rename exercises/{06.layout-effect/01.solution => 06.layout-computation/01.solution.layout-effect}/params.tsx (100%) rename exercises/{06.layout-effect/01.solution => 06.layout-computation/01.solution.layout-effect}/posts.tsx (100%) rename exercises/{06.layout-effect/01.solution => 06.layout-computation/01.solution.layout-effect}/tooltip.tsx (100%) create mode 100644 exercises/06.layout-computation/FINISHED.mdx create mode 100644 exercises/06.layout-computation/README.mdx delete mode 100644 exercises/06.layout-effect/01.problem/README.mdx delete mode 100644 exercises/06.layout-effect/01.solution/README.mdx delete mode 100644 exercises/06.layout-effect/FINISHED.mdx delete mode 100644 exercises/06.layout-effect/README.mdx diff --git a/exercises/05.portals/01.problem.create/tooltip.tsx b/exercises/05.portals/01.problem.create/tooltip.tsx index 727e7bf1..eaf049df 100644 --- a/exercises/05.portals/01.problem.create/tooltip.tsx +++ b/exercises/05.portals/01.problem.create/tooltip.tsx @@ -22,7 +22,6 @@ export default function Tooltip({ if (!rect) return const { height } = rect setTooltipHeight(height) - console.log('Measured tooltip height: ' + height) }, []) let tooltipX = 0 diff --git a/exercises/05.portals/01.solution.create/tooltip.tsx b/exercises/05.portals/01.solution.create/tooltip.tsx index 026fd2ed..d87c7647 100644 --- a/exercises/05.portals/01.solution.create/tooltip.tsx +++ b/exercises/05.portals/01.solution.create/tooltip.tsx @@ -23,7 +23,6 @@ export default function Tooltip({ if (!rect) return const { height } = rect setTooltipHeight(height) - console.log('Measured tooltip height: ' + height) }, []) let tooltipX = 0 diff --git a/exercises/06.layout-computation/01.problem.layout-effect/README.mdx b/exercises/06.layout-computation/01.problem.layout-effect/README.mdx new file mode 100644 index 00000000..3ae510fc --- /dev/null +++ b/exercises/06.layout-computation/01.problem.layout-effect/README.mdx @@ -0,0 +1,27 @@ +# useLayoutEffect + +👨‍💼 Our tooltip is great, but we do need to make measurements when we display it. +We do this in a `useEffect` hook now with code like this: + +```tsx +useEffect(() => { + const rect = ref.current?.getBoundingClientRect() + if (!rect) return + const { height } = rect + setTooltipHeight(height) +}, []) +``` + +That `height` is used to determine whether the tooltip should appear above or +below the target element (the heart in our case). + +Kellie 🧝‍♂️ noticed on low-end devices, they're seeing a little flicker +so she's added an arbitrary slowdown to our +component to simulate that problem. To reproduce the problem, simply hover over +a heart and you'll notice it starts at the bottom of the heart and then flickers +to the top (if there's room on the top of the heart). + +So your job is simple. Change `useEffect` to `useLayoutEffect` and that should +fix things. + +📜 Parts of this exercise was lifted from [the React docs](https://react.dev/reference/react/useLayoutEffect#measuring-layout-before-the-browser-repaints-the-screen) diff --git a/exercises/06.layout-effect/01.problem/form.tsx b/exercises/06.layout-computation/01.problem.layout-effect/form.tsx similarity index 100% rename from exercises/06.layout-effect/01.problem/form.tsx rename to exercises/06.layout-computation/01.problem.layout-effect/form.tsx diff --git a/exercises/06.layout-effect/01.problem/index.css b/exercises/06.layout-computation/01.problem.layout-effect/index.css similarity index 100% rename from exercises/06.layout-effect/01.problem/index.css rename to exercises/06.layout-computation/01.problem.layout-effect/index.css diff --git a/exercises/06.layout-effect/01.problem/index.tsx b/exercises/06.layout-computation/01.problem.layout-effect/index.tsx similarity index 100% rename from exercises/06.layout-effect/01.problem/index.tsx rename to exercises/06.layout-computation/01.problem.layout-effect/index.tsx diff --git a/exercises/06.layout-effect/01.problem/params.tsx b/exercises/06.layout-computation/01.problem.layout-effect/params.tsx similarity index 100% rename from exercises/06.layout-effect/01.problem/params.tsx rename to exercises/06.layout-computation/01.problem.layout-effect/params.tsx diff --git a/exercises/06.layout-effect/01.problem/posts.tsx b/exercises/06.layout-computation/01.problem.layout-effect/posts.tsx similarity index 100% rename from exercises/06.layout-effect/01.problem/posts.tsx rename to exercises/06.layout-computation/01.problem.layout-effect/posts.tsx diff --git a/exercises/06.layout-effect/01.problem/tooltip.tsx b/exercises/06.layout-computation/01.problem.layout-effect/tooltip.tsx similarity index 93% rename from exercises/06.layout-effect/01.problem/tooltip.tsx rename to exercises/06.layout-computation/01.problem.layout-effect/tooltip.tsx index 8570385a..d4ce78c5 100644 --- a/exercises/06.layout-effect/01.problem/tooltip.tsx +++ b/exercises/06.layout-computation/01.problem.layout-effect/tooltip.tsx @@ -18,6 +18,8 @@ export default function Tooltip({ const ref = useRef(null) const [tooltipHeight, setTooltipHeight] = useState(0) + // 🐨 change this to useLayoutEffect to ensure it runs synchronously after the + // DOM has been updated so the user doesn't see the tooltip jump around. useEffect(() => { const rect = ref.current?.getBoundingClientRect() if (!rect) return diff --git a/exercises/06.layout-computation/01.solution.layout-effect/README.mdx b/exercises/06.layout-computation/01.solution.layout-effect/README.mdx new file mode 100644 index 00000000..0d089545 --- /dev/null +++ b/exercises/06.layout-computation/01.solution.layout-effect/README.mdx @@ -0,0 +1,13 @@ +# useLayoutEffect + +👨‍💼 Have you ever heard of the mechanic who charged $200 when all he did was +tighten a screw? The customer was outraged and asked for an itemized bill. The +mechanic sent him an invoice that read: + +``` +Tightening a screw: $1 +Knowing which screw to tighten: $199 +``` + +Even though this exercise was really easy, knowing when to use `useLayoutEffect` +is the hard part. It's like knowing which screw to tighten. Good job! diff --git a/exercises/06.layout-effect/01.solution/form.tsx b/exercises/06.layout-computation/01.solution.layout-effect/form.tsx similarity index 100% rename from exercises/06.layout-effect/01.solution/form.tsx rename to exercises/06.layout-computation/01.solution.layout-effect/form.tsx diff --git a/exercises/06.layout-effect/01.solution/index.css b/exercises/06.layout-computation/01.solution.layout-effect/index.css similarity index 100% rename from exercises/06.layout-effect/01.solution/index.css rename to exercises/06.layout-computation/01.solution.layout-effect/index.css diff --git a/exercises/06.layout-effect/01.solution/index.tsx b/exercises/06.layout-computation/01.solution.layout-effect/index.tsx similarity index 100% rename from exercises/06.layout-effect/01.solution/index.tsx rename to exercises/06.layout-computation/01.solution.layout-effect/index.tsx diff --git a/exercises/06.layout-effect/01.solution/params.tsx b/exercises/06.layout-computation/01.solution.layout-effect/params.tsx similarity index 100% rename from exercises/06.layout-effect/01.solution/params.tsx rename to exercises/06.layout-computation/01.solution.layout-effect/params.tsx diff --git a/exercises/06.layout-effect/01.solution/posts.tsx b/exercises/06.layout-computation/01.solution.layout-effect/posts.tsx similarity index 100% rename from exercises/06.layout-effect/01.solution/posts.tsx rename to exercises/06.layout-computation/01.solution.layout-effect/posts.tsx diff --git a/exercises/06.layout-effect/01.solution/tooltip.tsx b/exercises/06.layout-computation/01.solution.layout-effect/tooltip.tsx similarity index 100% rename from exercises/06.layout-effect/01.solution/tooltip.tsx rename to exercises/06.layout-computation/01.solution.layout-effect/tooltip.tsx diff --git a/exercises/06.layout-computation/FINISHED.mdx b/exercises/06.layout-computation/FINISHED.mdx new file mode 100644 index 00000000..0c0d0ff2 --- /dev/null +++ b/exercises/06.layout-computation/FINISHED.mdx @@ -0,0 +1,3 @@ +# Layout Computation + +👨‍💼 Hey... You're awesome. 😎 diff --git a/exercises/06.layout-computation/README.mdx b/exercises/06.layout-computation/README.mdx new file mode 100644 index 00000000..9f4c3c75 --- /dev/null +++ b/exercises/06.layout-computation/README.mdx @@ -0,0 +1,26 @@ +# Layout Computation + +Sometimes you need to compute the layout of some UI before it is actually +displayed. This is often necessary if the size, position, or location of your UI +depends on the size, position, or location of the other elements on the page or +even itself (like the contents of a tooltip). + +The trouble is, sometimes you don't know the size, position, or location of the +other elements on the page until the layout has been computed. So what happens +is you render the UI, then you make your measurements, then you re-render the UI +with the new measurements. This is inefficient and can cause flickering. + +To avoid this problem in React, you can use the `useLayoutEffect` hook. This +hook is designed with this specific use case in mind and is not a hook you'll +find yourself needing very often. + +It literally has the same API as `useEffect`, but it runs synchronously after +the DOM has been updated. You may recall from the `useEffect` exercise, the +[React flow diagram](https://github.com/donavon/hook-flow): + +![React Flow diagram showing mount, update, unmount](https://github-production-user-asset-6210df.s3.amazonaws.com/1500684/295689283-b9ecdd1d-ce28-446b-84ad-6b264d4be8e4.png) + +The `useLayoutEffect` hook runs after the DOM has been updated but before the +browser has had a chance to paint the screen. This means you can make your +measurements and then render the UI with the correct measurements before the +user sees anything. diff --git a/exercises/06.layout-effect/01.problem/README.mdx b/exercises/06.layout-effect/01.problem/README.mdx deleted file mode 100644 index 8350c7c7..00000000 --- a/exercises/06.layout-effect/01.problem/README.mdx +++ /dev/null @@ -1 +0,0 @@ -# createPortal diff --git a/exercises/06.layout-effect/01.solution/README.mdx b/exercises/06.layout-effect/01.solution/README.mdx deleted file mode 100644 index 8350c7c7..00000000 --- a/exercises/06.layout-effect/01.solution/README.mdx +++ /dev/null @@ -1 +0,0 @@ -# createPortal diff --git a/exercises/06.layout-effect/FINISHED.mdx b/exercises/06.layout-effect/FINISHED.mdx deleted file mode 100644 index e69de29b..00000000 diff --git a/exercises/06.layout-effect/README.mdx b/exercises/06.layout-effect/README.mdx deleted file mode 100644 index 9ea9af1d..00000000 --- a/exercises/06.layout-effect/README.mdx +++ /dev/null @@ -1,3 +0,0 @@ -# Layout Computation - -📜 Parts of this exercise was lifted from [the React docs](https://react.dev/reference/react/useLayoutEffect#measuring-layout-before-the-browser-repaints-the-screen)