Skip to content

Commit

Permalink
add context optimization exercises
Browse files Browse the repository at this point in the history
  • Loading branch information
kentcdodds committed Feb 24, 2024
1 parent 5818400 commit 3983fd2
Show file tree
Hide file tree
Showing 405 changed files with 1,522 additions and 98 deletions.
1 change: 1 addition & 0 deletions exercises/01.composition/01.problem.reuse/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Reusing Elements
24 changes: 24 additions & 0 deletions exercises/01.composition/01.problem.reuse/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useState } from 'react'
import * as ReactDOM from 'react-dom/client'

function Footer() {
return <footer>I am the footer</footer>
}

// 🐨 assign a <Footer /> to a footer variable here

function App() {
const [count, setCount] = useState(0)
const increment = () => setCount(c => c + 1)
return (
<div>
<button onClick={increment}>The count is {count}</button>
{/* 🐨 change this to an interpolation and interpolate the footer */}
<Footer />
</div>
)
}

const rootEl = document.createElement('div')
document.body.append(rootEl)
ReactDOM.createRoot(rootEl).render(<App />)
20 changes: 20 additions & 0 deletions exercises/01.composition/01.problem.reuse/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"include": ["**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2023"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"module": "ES2022",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"target": "ES2022",
"strict": true,
"noImplicitAny": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"allowImportingTsExtensions": true,
"noEmit": true,
}
}
1 change: 1 addition & 0 deletions exercises/01.composition/01.solution.reuse/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Reusing Elements
23 changes: 23 additions & 0 deletions exercises/01.composition/01.solution.reuse/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useState } from 'react'
import * as ReactDOM from 'react-dom/client'

function Footer() {
return <footer>I am the footer</footer>
}

const footer = <Footer />

function App() {
const [count, setCount] = useState(0)
const increment = () => setCount(c => c + 1)
return (
<div>
<button onClick={increment}>The count is {count}</button>
{footer}
</div>
)
}

const rootEl = document.createElement('div')
document.body.append(rootEl)
ReactDOM.createRoot(rootEl).render(<App />)
20 changes: 20 additions & 0 deletions exercises/01.composition/01.solution.reuse/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"include": ["**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2023"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"module": "ES2022",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"target": "ES2022",
"strict": true,
"noImplicitAny": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"allowImportingTsExtensions": true,
"noEmit": true,
}
}
1 change: 1 addition & 0 deletions exercises/01.composition/02.problem.props/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Element Props
48 changes: 48 additions & 0 deletions exercises/01.composition/02.problem.props/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useState } from 'react'
import * as ReactDOM from 'react-dom/client'

function Footer({ color }: { color: string }) {
return <footer style={{ color }}>I am the ({color}) footer</footer>
}

// 💣 delete this variable
const footer = <Footer color="black" />

// 🐨 make the Main component accept a footer prop
function Main() {
const [count, setCount] = useState(0)
const increment = () => setCount(c => c + 1)
return (
<div>
<button onClick={increment}>The count is {count}</button>
{footer}
</div>
)
}

function App() {
const [color, setColor] = useState('black')
return (
<div>
<div>
<p>Set the footer color:</p>
<div style={{ display: 'flex', gap: 4 }}>
<button onClick={() => setColor('black')}>Black</button>
<button onClick={() => setColor('blue')}>Blue</button>
<button onClick={() => setColor('green')}>Green</button>
</div>
</div>
{/* 🐨 pass the footer prop so you can dynamically determine the color */}
<Main />
</div>
)
}

const rootEl = document.createElement('div')
document.body.append(rootEl)
ReactDOM.createRoot(rootEl).render(<App />)

/*
eslint
@typescript-eslint/no-unused-vars: "off",
*/
20 changes: 20 additions & 0 deletions exercises/01.composition/02.problem.props/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"include": ["**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2023"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"module": "ES2022",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"target": "ES2022",
"strict": true,
"noImplicitAny": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"allowImportingTsExtensions": true,
"noEmit": true,
}
}
1 change: 1 addition & 0 deletions exercises/01.composition/02.solution.props/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Element Props
38 changes: 38 additions & 0 deletions exercises/01.composition/02.solution.props/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useState } from 'react'
import * as ReactDOM from 'react-dom/client'

function Footer({ color }: { color: string }) {
return <footer style={{ color }}>I am the ({color}) footer</footer>
}

function Main({ footer }: { footer: React.ReactNode }) {
const [count, setCount] = useState(0)
const increment = () => setCount(c => c + 1)
return (
<div>
<button onClick={increment}>The count is {count}</button>
{footer}
</div>
)
}

function App() {
const [color, setColor] = useState('black')
return (
<div>
<div>
<p>Set the footer color:</p>
<div style={{ display: 'flex', gap: 4 }}>
<button onClick={() => setColor('black')}>Black</button>
<button onClick={() => setColor('blue')}>Blue</button>
<button onClick={() => setColor('green')}>Green</button>
</div>
</div>
<Main footer={<Footer color={color} />} />
</div>
)
}

const rootEl = document.createElement('div')
document.body.append(rootEl)
ReactDOM.createRoot(rootEl).render(<App />)
20 changes: 20 additions & 0 deletions exercises/01.composition/02.solution.props/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"include": ["**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2023"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"module": "ES2022",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"target": "ES2022",
"strict": true,
"noImplicitAny": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"allowImportingTsExtensions": true,
"noEmit": true,
}
}
1 change: 1 addition & 0 deletions exercises/01.composition/03.problem.context/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Context
50 changes: 50 additions & 0 deletions exercises/01.composition/03.problem.context/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useState } from 'react'
import * as ReactDOM from 'react-dom/client'

// 🐨 create a ColorContext

// 🐨 remove the prop
function Footer({ color }: { color: string }) {
// 🐨 get the color from the ColorContext
return <footer style={{ color }}>I am the ({color}) footer</footer>
}

function Main({ footer }: { footer: React.ReactNode }) {
const [count, setCount] = useState(0)
const increment = () => setCount(c => c + 1)
return (
<div>
<button onClick={increment}>The count is {count}</button>
{footer}
</div>
)
}

// 🐨 create the <Footer /> out here and assign it to a footer variable

function App() {
const [color, setColor] = useState('black')
const [appCount, setAppCount] = useState(0)
// 🐨 wrap all this with the ColorContext provider and pass the color
return (
<div>
<div>
<p>Set the footer color:</p>
<div style={{ display: 'flex', gap: 4 }}>
<button onClick={() => setColor('black')}>Black</button>
<button onClick={() => setColor('blue')}>Blue</button>
<button onClick={() => setColor('green')}>Green</button>
</div>
</div>
<button onClick={() => setAppCount(c => c + 1)}>
The app count is {appCount}
</button>
{/* 🐨 remove the color prop and move this outside the component again */}
<Main footer={<Footer color={color} />} />
</div>
)
}

const rootEl = document.createElement('div')
document.body.append(rootEl)
ReactDOM.createRoot(rootEl).render(<App />)
20 changes: 20 additions & 0 deletions exercises/01.composition/03.problem.context/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"include": ["**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2023"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"module": "ES2022",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"target": "ES2022",
"strict": true,
"noImplicitAny": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"allowImportingTsExtensions": true,
"noEmit": true,
}
}
1 change: 1 addition & 0 deletions exercises/01.composition/03.solution.context/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Context
55 changes: 55 additions & 0 deletions exercises/01.composition/03.solution.context/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { createContext, use, useState } from 'react'
import * as ReactDOM from 'react-dom/client'

const ColorContext = createContext<string | null>(null)

function useColor() {
const color = use(ColorContext)
if (!color) throw new Error('ColorContext not found')
return color
}

function Footer() {
const color = useColor()
return <footer style={{ color }}>I am the ({color}) footer</footer>
}

function Main({ footer }: { footer: React.ReactNode }) {
const [count, setCount] = useState(0)
const increment = () => setCount(c => c + 1)
return (
<div>
<button onClick={increment}>The count is {count}</button>
{footer}
</div>
)
}

const footer = <Footer />

function App() {
const [color, setColor] = useState('black')
const [appCount, setAppCount] = useState(0)
return (
<ColorContext.Provider value={color}>
<div>
<div>
<p>Set the footer color:</p>
<div style={{ display: 'flex', gap: 4 }}>
<button onClick={() => setColor('black')}>Black</button>
<button onClick={() => setColor('blue')}>Blue</button>
<button onClick={() => setColor('green')}>Green</button>
</div>
</div>
<button onClick={() => setAppCount(c => c + 1)}>
The app count is {appCount}
</button>
<Main footer={footer} />
</div>
</ColorContext.Provider>
)
}

const rootEl = document.createElement('div')
document.body.append(rootEl)
ReactDOM.createRoot(rootEl).render(<App />)
20 changes: 20 additions & 0 deletions exercises/01.composition/03.solution.context/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"include": ["**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2023"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"module": "ES2022",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"target": "ES2022",
"strict": true,
"noImplicitAny": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"allowImportingTsExtensions": true,
"noEmit": true,
}
}
1 change: 1 addition & 0 deletions exercises/01.composition/04.problem.use-memo/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Memoize Elements
Loading

0 comments on commit 3983fd2

Please sign in to comment.