Skip to content

Commit ed13c89

Browse files
committed
Fix small typos
1 parent 101299c commit ed13c89

File tree

7 files changed

+8
-8
lines changed

7 files changed

+8
-8
lines changed

src/pages/useDarkMode.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ sandbox: https://codesandbox.io/s/p33j1m0mxj
88
links:
99
- url: https://github.com/donavon/use-dark-mode
1010
name: donavon/use-dark-mode
11-
description: A more configurable implemention of this hook that syncs changes across browser tabs and handles SSR. Provided much of the code and inspiration for this post.
11+
description: A more configurable implementation of this hook that syncs changes across browser tabs and handles SSR. Provided much of the code and inspiration for this post.
1212
code: "\/\/ Usage\r\nfunction App() {\r\n const [darkMode, setDarkMode] = useDarkMode();\r\n\r\n return (\r\n <div>\r\n <div className=\"navbar\">\r\n <Toggle darkMode={darkMode} setDarkMode={setDarkMode} \/>\r\n <\/div>\r\n <Content \/>\r\n <\/div>\r\n );\r\n}\r\n\r\n\/\/ Hook\r\nfunction useDarkMode() {\r\n \/\/ Use our useLocalStorage hook to persist state through a page refresh.\r\n \/\/ Read the recipe for this hook to learn more: usehooks.com\/useLocalStorage\r\n const [enabledState, setEnabledState] = useLocalStorage('dark-mode-enabled');\r\n\r\n \/\/ See if user has set a browser or OS preference for dark mode.\r\n \/\/ The usePrefersDarkMode hook composes a useMedia hook (see code below).\r\n const prefersDarkMode = usePrefersDarkMode();\r\n\r\n \/\/ If enabledState is defined use it, otherwise fallback to prefersDarkMode.\r\n \/\/ This allows user to override OS level setting on our website.\r\n const enabled =\r\n typeof enabledState !== 'undefined' ? enabledState : prefersDarkMode;\r\n\r\n \/\/ Fire off effect that add\/removes dark mode class\r\n useEffect(\r\n () => {\r\n const className = 'dark-mode';\r\n const element = window.document.body;\r\n if (enabled) {\r\n element.classList.add(className);\r\n } else {\r\n element.classList.remove(className);\r\n }\r\n },\r\n [enabled] \/\/ Only re-call effect when value changes\r\n );\r\n\r\n \/\/ Return enabled state and setter\r\n return [enabled, setEnabledState];\r\n}\r\n\r\n\/\/ Compose our useMedia hook to detect dark mode preference.\r\n\/\/ The API for useMedia looks a bit weird, but that's because ...\r\n\/\/ ... it was designed to support multiple media queries and return values.\r\n\/\/ Thanks to hook composition we can hide away that extra complexity!\r\n\/\/ Read the recipe for useMedia to learn more: usehooks.com\/useMedia\r\nfunction usePrefersDarkMode() {\r\n return useMedia(['(prefers-color-scheme: dark)'], [true], false);\r\n}"
1313
---
1414

src/pages/useDebounce.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ sandbox: https://codesandbox.io/s/711r1zmq50
77
code: "import { useState, useEffect, useRef } from 'react';\r\n\r\n\/\/ Usage\r\nfunction App() {\r\n \/\/ State and setters for ...\r\n \/\/ Search term\r\n const [searchTerm, setSearchTerm] = useState('');\r\n \/\/ API search results\r\n const [results, setResults] = useState([]);\r\n \/\/ Searching status (whether there is pending API request)\r\n const [isSearching, setIsSearching] = useState(false);\r\n \/\/ Debounce search term so that it only gives us latest value ...\r\n \/\/ ... if searchTerm has not been updated within last 500ms.\r\n \/\/ The goal is to only have the API call fire when user stops typing ...\r\n \/\/ ... so that we aren't hitting our API rapidly.\r\n const debouncedSearchTerm = useDebounce(searchTerm, 500);\r\n \r\n \/\/ Effect for API call \r\n useEffect(\r\n () => {\r\n if (debouncedSearchTerm) {\r\n setIsSearching(true);\r\n searchCharacters(debouncedSearchTerm).then(results => {\r\n setIsSearching(false);\r\n setResults(results);\r\n });\r\n } else {\r\n setResults([]);\r\n }\r\n },\r\n [debouncedSearchTerm] \/\/ Only call effect if debounced search term changes\r\n );\r\n\r\n return (\r\n <div>\r\n <input\r\n placeholder=\"Search Marvel Comics\"\r\n onChange={e => setSearchTerm(e.target.value)}\r\n \/>\r\n \r\n {isSearching && <div>Searching ...<\/div>}\r\n\r\n {results.map(result => (\r\n <div key={result.id}>\r\n <h4>{result.title}<\/h4>\r\n <img\r\n src={`${result.thumbnail.path}\/portrait_incredible.${\r\n result.thumbnail.extension\r\n }`}\r\n \/>\r\n <\/div>\r\n ))}\r\n <\/div>\r\n );\r\n}\r\n\r\n\/\/ API search function\r\nfunction searchCharacters(search) {\r\n const apiKey = 'f9dfb1e8d466d36c27850bedd2047687';\r\n return fetch(\r\n `https:\/\/gateway.marvel.com\/v1\/public\/comics?apikey=${apiKey}&titleStartsWith=${search}`,\r\n {\r\n method: 'GET'\r\n }\r\n ) \r\n .then(r => r.json())\r\n .then(r => r.data.results)\r\n .catch(error => {\r\n console.error(error);\r\n return [];\r\n });\r\n}\r\n \r\n\/\/ Hook\r\nfunction useDebounce(value, delay) {\r\n \/\/ State and setters for debounced value\r\n const [debouncedValue, setDebouncedValue] = useState(value);\r\n\r\n useEffect(\r\n () => {\r\n \/\/ Update debounced value after delay\r\n const handler = setTimeout(() => {\r\n setDebouncedValue(value);\r\n }, delay);\r\n\r\n \/\/ Cancel the timeout if value changes (also on delay change or unmount)\r\n \/\/ This is how we prevent debounced value from updating if value is changed ...\r\n \/\/ .. within the delay period. Timeout gets cleared and restarted.\r\n return () => {\r\n clearTimeout(handler);\r\n };\r\n },\r\n [value, delay] \/\/ Only re-call effect if value or delay changes\r\n );\r\n\r\n return debouncedValue;\r\n}"
88
---
99

10-
This hook allows you to debounce any fast changing value. The debounced value will only reflect the latest value when the useDebounce hook has not been called for the specified time period. When used in conjuction with useEffect, as we do in the recipe below, you can easily ensure that expensive operations like API calls are not executed too frequently. The example below allows you to search the Marvel Comic API and uses useDebounce to prevent API calls from being fired on every keystroke. Be sure to theck out the [CodeSandbox demo](https://codesandbox.io/s/711r1zmq50) for this one. Hook code and inspiration from [github.com/xnimorz/use-debounce](https://github.com/xnimorz/use-debounce).
10+
This hook allows you to debounce any fast changing value. The debounced value will only reflect the latest value when the useDebounce hook has not been called for the specified time period. When used in conjunction with useEffect, as we do in the recipe below, you can easily ensure that expensive operations like API calls are not executed too frequently. The example below allows you to search the Marvel Comic API and uses useDebounce to prevent API calls from being fired on every keystroke. Be sure to check out the [CodeSandbox demo](https://codesandbox.io/s/711r1zmq50) for this one. Hook code and inspiration from [github.com/xnimorz/use-debounce](https://github.com/xnimorz/use-debounce).

src/pages/useMemo.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ code:
2727
=> setCount(count + 1)}>Increment</button>\r\n </div>\r\n );\r\n}"
2828
---
2929

30-
React has a built-in hook called useMemo that allows you to memoize expensive functions so that you can avoid calling them on every render. You simple pass in a function and an array of inputs and useMemo will only recompute the memoized value when one of the inputs has changed. In our example below we have an expensive function called computeLetterCount (for demo purposes we make it slow by including a large and completely unnecessary loop). When the current selected word changes you'll notice a delay as it has to recall computeLetterCount on the new word. We also have a separate counter that gets incremented everytime the increment button is clicked. When that counter is incremented you'll notice that there is zero lag between renders. This is because computeLetterCount is not called again. The input word hasn't changed and thus the cached value is returned. You'll probably want to check out the [CodeSandbox demo](https://codesandbox.io/s/jjxypyk86w) so you can see for yourself.
30+
React has a built-in hook called useMemo that allows you to memoize expensive functions so that you can avoid calling them on every render. You simple pass in a function and an array of inputs and useMemo will only recompute the memoized value when one of the inputs has changed. In our example below we have an expensive function called computeLetterCount (for demo purposes we make it slow by including a large and completely unnecessary loop). When the current selected word changes you'll notice a delay as it has to recall computeLetterCount on the new word. We also have a separate counter that gets incremented every time the increment button is clicked. When that counter is incremented you'll notice that there is zero lag between renders. This is because computeLetterCount is not called again. The input word hasn't changed and thus the cached value is returned. You'll probably want to check out the [CodeSandbox demo](https://codesandbox.io/s/jjxypyk86w) so you can see for yourself.

src/pages/useScript.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sandbox: https://codesandbox.io/s/pm28k14qlj
77
links:
88
- url: https://github.com/sesilio/react-script-loader-hoc/blob/master/src/index.js
99
name: react-script-loader-hoc
10-
description: HOC implemantion of same logic for the sake of comparison.
10+
description: HOC implementation of same logic for the sake of comparison.
1111
- url: https://github.com/palmerhq/the-platform#usescript
1212
name: useScript from palmerhq/the-platform
1313
description: Similar hook but returns a promise for use with React Suspense.
@@ -41,4 +41,4 @@ code:
4141
changes\r\n );\r\n\r\n return [state.loaded, state.error];\r\n}"
4242
---
4343

44-
This hook makes it super easy to dynamically load an external script and know when its loaded. This is useful when you need to interact with a 3rd party libary (Stripe, Google Analytics, etc) and you'd prefer to load the script when needed rather then include it in the document head for every page request. In the example below we wait until the script has loaded successfully before calling a function declared in the script. If you're interested in seeing how this would look if implemented as a Higher Order Component then check out the [source of react-script-loader-hoc](https://github.com/sesilio/react-script-loader-hoc/blob/master/src/index.js). I personally find it much more readable as a hook. Another advantage is because it's so easy to call the same hook multiple times to load multiple different scripts, unlike the HOC implementation, we can skip adding support for passing in multiple src strings.
44+
This hook makes it super easy to dynamically load an external script and know when its loaded. This is useful when you need to interact with a 3rd party library (Stripe, Google Analytics, etc) and you'd prefer to load the script when needed rather then include it in the document head for every page request. In the example below we wait until the script has loaded successfully before calling a function declared in the script. If you're interested in seeing how this would look if implemented as a Higher Order Component then check out the [source of react-script-loader-hoc](https://github.com/sesilio/react-script-loader-hoc/blob/master/src/index.js). I personally find it much more readable as a hook. Another advantage is because it's so easy to call the same hook multiple times to load multiple different scripts, unlike the HOC implementation, we can skip adding support for passing in multiple src strings.

src/pages/useSpring.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sandbox: https://codesandbox.io/s/6jlvz1j5q3
77
links:
88
- url: http://react-spring.surge.sh
99
name: react-spring
10-
description: Offical docs with lots of fun animation examples. See section about the <a target="_blank" href="http://react-spring.surge.sh/manual">useSpring hook here</a>.
10+
description: Official docs with lots of fun animation examples. See section about the <a target="_blank" href="http://react-spring.surge.sh/manual">useSpring hook here</a>.
1111
- url: https://codesandbox.io/s/j1zol1nrq3
1212
name: Card Demo
1313
description: Original useSpring demo that my code is based on by <a target="_blank" href="https://twitter.com/0xca0a">0xca0a</a>.

src/pages/useTheme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ links:
1111
code: "import { useLayoutEffect } from 'react';\r\nimport '.\/styles.scss'; \/\/ -> https:\/\/codesandbox.io\/s\/15mko9187\r\n\r\n\/\/ Usage\r\nconst theme = {\r\n 'button-padding': '16px',\r\n 'button-font-size': '14px',\r\n 'button-border-radius': '4px',\r\n 'button-border': 'none',\r\n 'button-color': '#FFF',\r\n 'button-background': '#6772e5',\r\n 'button-hover-border': 'none',\r\n 'button-hover-color': '#FFF'\r\n};\r\n\r\nfunction App() {\r\n useTheme(theme);\r\n\r\n return (\r\n <div>\r\n <button className=\"button\">Button<\/button>\r\n <\/div>\r\n );\r\n}\r\n\r\n\/\/ Hook\r\nfunction useTheme(theme) {\r\n useLayoutEffect(\r\n () => {\r\n \/\/ Iterate through each value in theme object\r\n for (const key in theme) {\r\n \/\/ Update css variables in document's root element\r\n document.documentElement.style.setProperty(`--${key}`, theme[key]);\r\n }\r\n },\r\n [theme] \/\/ Only call again if theme object reference changes\r\n );\r\n}"
1212
---
1313

14-
This hook makes it easy to dynamically change the appearance of your app using CSS variables. You simply pass in an object containing key/value pairs of the CSS variables you'd like to update and the hook updates each variable in the document's root element. This is useful in situations where you can't define styles inline (no psudeoclass support) and there are too many style permutations to include each theme in your stylesheet (such as a web app that lets users customize the look of their profile). It's worth noting that many css-in-js libraries support dynamic styles out of the box, but it's interesting to experiment with how this can be done with just CSS variables and a React Hook. The example below is intentionally very simple, but you could imagine the theme object being stored in state or fetched from an API. Be sure to check out the [CodeSandbox demo](https://codesandbox.io/s/15mko9187) for a more interesting example and to see the accompanying stylesheet.
14+
This hook makes it easy to dynamically change the appearance of your app using CSS variables. You simply pass in an object containing key/value pairs of the CSS variables you'd like to update and the hook updates each variable in the document's root element. This is useful in situations where you can't define styles inline (no pseudo class support) and there are too many style permutations to include each theme in your stylesheet (such as a web app that lets users customize the look of their profile). It's worth noting that many css-in-js libraries support dynamic styles out of the box, but it's interesting to experiment with how this can be done with just CSS variables and a React Hook. The example below is intentionally very simple, but you could imagine the theme object being stored in state or fetched from an API. Be sure to check out the [CodeSandbox demo](https://codesandbox.io/s/15mko9187) for a more interesting example and to see the accompanying stylesheet.

src/pages/useWhyDidYouUpdate.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ sandbox: https://codesandbox.io/s/kx83n7201o
77
code: "import { useState, useEffect, useRef } from 'react';\r\n\r\n\/\/ Let's pretend this <Counter> component is expensive to re-render so ...\r\n\/\/ ... we wrap with React.memo, but we're still seeing performance issues :\/\r\n\/\/ So we add useWhyDidYouUpdate and check our console to see what's going on.\r\nconst Counter = React.memo(props => {\r\n useWhyDidYouUpdate('Counter', props);\r\n return <div style={props.style}>{props.count}<\/div>;\r\n});\r\n\r\nfunction App() {\r\n const [count, setCount] = useState(0);\r\n const [userId, setUserId] = useState(0);\r\n\r\n \/\/ Our console output tells use that the style prop for <Counter> ...\r\n \/\/ ... changes on every render, even when we only change userId state by ...\r\n \/\/ ... clicking the \"switch user\" button. Oh of course! That's because the\r\n \/\/ ... counterStyle object is being re-created on every render.\r\n \/\/ Thanks to our hook we figured this out and realized we should probably ...\r\n \/\/ ... move this object outside of the component body.\r\n const counterStyle = {\r\n fontSize: '3rem',\r\n color: 'red'\r\n };\r\n\r\n return (\r\n <div>\r\n <div className=\"counter\">\r\n <Counter count={count} style={counterStyle} \/>\r\n <button onClick={() => setCount(count + 1)}>Increment<\/button>\r\n <\/div>\r\n <div className=\"user\">\r\n <img src={`http:\/\/i.pravatar.cc\/80?img=${userId}`} \/>\r\n <button onClick={() => setUserId(userId + 1)}>Switch User<\/button>\r\n <\/div>\r\n <\/div>\r\n );\r\n}\r\n\r\n\/\/ Hook\r\nfunction useWhyDidYouUpdate(name, props) {\r\n \/\/ Get a mutable ref object where we can store props ...\r\n \/\/ ... for comparison next time this hook runs.\r\n const previousProps = useRef();\r\n\r\n useEffect(() => {\r\n if (previousProps.current) {\r\n \/\/ Get all keys from previous and current props\r\n const allKeys = Object.keys({ ...previousProps.current, ...props });\r\n \/\/ Use this object to keep track of changed props\r\n const changesObj = {};\r\n \/\/ Iterate through keys\r\n allKeys.forEach(key => {\r\n \/\/ If previous is different from current\r\n if (previousProps.current[key] !== props[key]) {\r\n \/\/ Add to changesObj\r\n changesObj[key] = {\r\n from: previousProps.current[key],\r\n to: props[key]\r\n };\r\n }\r\n });\r\n\r\n \/\/ If changesObj not empty then output to console\r\n if (Object.keys(changesObj).length) {\r\n console.log('[why-did-you-update]', name, changesObj);\r\n }\r\n }\r\n\r\n \/\/ Finally update previousProps with current props for next hook call\r\n previousProps.current = props;\r\n });\r\n}"
88
---
99

10-
This hook makes it easy to see which prop changes are causing a component to re-render. If a function is particularly expensive to run and you know it renders the same results given the same props you can use the `React.memo` higher order component, as we've done with the `Counter` component in the below example. In this case if you're still seeing re-renders that seem uneccessary you can drop in the `useWhyDidYouUpdate` hook and check your console to see which props changed between renders and view their previous/current values. Pretty nifty huh?
10+
This hook makes it easy to see which prop changes are causing a component to re-render. If a function is particularly expensive to run and you know it renders the same results given the same props you can use the `React.memo` higher order component, as we've done with the `Counter` component in the below example. In this case if you're still seeing re-renders that seem unnecessary you can drop in the `useWhyDidYouUpdate` hook and check your console to see which props changed between renders and view their previous/current values. Pretty nifty huh?
1111
<br/><br/>
1212
A huge thanks to Bruno Lemos for the [idea and original code](https://twitter.com/brunolemos/status/1090377532845801473). You can also see it in action in the [CodeSandbox demo](https://codesandbox.io/s/kx83n7201o).

0 commit comments

Comments
 (0)