feat(curriculum): videos and transcripts for understanding react effects lectures (#59485)

Co-authored-by: Dario-DC <105294544+Dario-DC@users.noreply.github.com>
This commit is contained in:
Tom
2025-04-07 11:20:05 -05:00
committed by GitHub
parent 90ee92699a
commit 7da7dc034e
3 changed files with 357 additions and 11 deletions

View File

@@ -2,13 +2,112 @@
id: 67d1a82dad69dc95546e5f0d
title: How Do You Reference Values Using Refs?
challengeType: 11
videoId: nVAaxZ34khk
videoId: gA0MGdlEubs
dashedName: how-do-you-reference-values-using-refs
---
# --description--
Watch the video lecture and answer the questions below.
Watch the video or read the transcript and answer the questions below.
# --transcript--
How do you reference values using refs?
In React, there may be situations where you need direct access to a DOM element. That's where "refs" come in handy. Refs can also store mutable values, but state is a better choice for that.
In vanilla JavaScript, you used the `getElementById()` and `querySelector()` methods to access DOM elements. But in React, you use refs to access elements in the DOM.
One of the main differences is that, with refs, you don't need identifiers like IDs and classes to reference elements.
So, how can you create and use refs? React provides a `useRef()` hook that lets you do just that. 
The first step is to import the hook from React:
```js
import { useRef } from "react";
```
Next, you need to create a variable that holds the ref with the initial value of the ref inside the `useRef` hook, say a `sectionRef` initialized to `null`:
```js
const sectionRef = useRef(null);
```
The final thing to do is to attach the ref variable to the element in your JSX by using the `ref` attribute:
```js
<section ref={sectionRef}>
{/* Section content */}
</section>
```
If you log the ref to the console, you'll see it's an object with the current value, in this case, `null`:
```js
console.log(sectionRef); // { current: null }
```
You can also log the current value to the console with the `current` property so you can see the value directly:
```js
console.log(sectionRef.current); // null
```
The subsequent values of the ref depend on the component lifecycle. 
For example, the initial value of `sectionRef` will always be `null` because that's what it was initialized to. After the component is mounted, the value of the ref will be the `section` element the ref is attached to.
If the component is unmounted, the ref's value goes back to the initial value of `null`.
A typical example to showcase a ref is to focus an input element on render, or by clicking a button.
Here's how to do that when you click a button:
```js
import { useRef } from "react";
const Focus = () => {
const inputRef = useRef(null);
const handleFocus = () => {
if (inputRef.current) {
inputRef.current.focus();
}
};
return (
<div>
<input ref={inputRef} type="text" placeholder="Enter text" />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
};
export default Focus;
```
In the code above, the `inputRef` is created and attached to the `input` element. There's also a button with an `onClick` event that calls a `handleFocus` function.
All the `handleFocus` function does is call the `focus()` method on the `input` element. Note that, because `input` is a built-in component that comes with React, the actual `input` DOM element is set to the `current` property of the ref. So you call the `focus()` method with `input.current.focus()`.
Here are some best practices you should be aware of while working with refs:
- Use refs mainly to interact with the DOM. You can also use them for mutable data, but state is a better choice for that.
- Don't use refs for basic state management that is what `useState` is for.
- Make sure you check that `ref.current` exists before accessing its properties. Here's how to do that again:
```js
const handleFocus = () => {
if (inputRef.current) {
inputRef.current.focus();
}
};
```
This prevents errors in case the ref is accessed before it is attached to the DOM or after it is removed.
# --questions--
@@ -86,7 +185,7 @@ Think about how refs store a mutable object with a key for accessing the `curren
## --text--
What is the value of the ref when the component is mounted?
What is the value of the ref after the component is mounted?
## --answers--

View File

@@ -2,13 +2,128 @@
id: 67d1ec6711b62f1cc5cc52e1
title: What Are Effects in React, and How Does the useEffect Hook Work?
challengeType: 11
videoId: nVAaxZ34khk
videoId: Dtd_8qxFM1w
dashedName: what-are-effects-in-react-and-how-does-the-useeffect-hook-work
---
# --description--
Watch the lecture video and answer the questions below.
Watch the video or read the transcript and answer the questions below.
# --transcript--
What are effects in React, and how does the `useEffect` hook work?
In React, an effect is anything that happens outside the component rendering process. That is, anything React does not handle directly as part of rendering the UI.
Common examples include fetching data, updating the browser tab's title, reading from or writing to the browser's local storage, getting the user's location, and much more. These operations interact with the outside world and are known as side effects.
React provides the `useEffect` hook to let you handle those side effects. `useEffect` lets you run a function after the component renders or updates.
Let's see how the `useEffect` hook works and why it's essential for modern React development.
To use the `useEffect` hook, you first need to import it:
```js
import { useEffect } from "react";
```
Then you use it as a function, like this:
```js
useEffect(() => {
// Your side effect logic (usually a function) here
}, [dependencies]);
```
The effect function runs after the component renders, while the optional `dependencies` argument controls when the effect runs.
Note that `dependencies` can be an array of "reactive values" (state, props, functions, variables, and so on), an empty array, or omitted entirely. Here's how all of those options control how `useEffect` works:
- If `dependencies` is an array that includes one or more reactive values, the effect will run whenever they change.
- If `dependencies` is an empty array, `useEffect` runs only once when the component first renders.
- If you omit `dependencies`, the effect runs every time the component renders or updates.
For example, in this `Counter` application, we don't pass in a `dependencies` argument, so the effect runs when the component renders and every time it updates:
```js
import { useState, useEffect } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Component renders");
});
return (
<div
style={{
display: "flex",
alignItems: "center",
flexDirection: "column",
}}
>
<h2>{count}</h2>
<div>
<button onClick={() => setCount(count + 1)}>Increase</button>
<button onClick={() => setCount(count - 1)}>Decrease</button>
</div>
</div>
);
};
export default Counter;
```
But if we pass in an empty array as a dependency, the effect only runs on the first render:
```js
useEffect(() => {
console.log('Component renders');
}, []);
```
If you pass in the `count` state as a dependency, the effect runs when the component first render, and when `count` changes:
```js
useEffect(() => {
document.title = `The current count is ${count}`;
console.log('component renders');
}, [count]);
```
Note that, if the effect you set up persists beyond the component's rendering lifecycle, you might need another function to "clean up" that function after the component renders or updates.
For example, if your effect function uses `setInterval()`, sets an event listener like `window.addEventListener()`, or connects to a server, you'll need a cleanup function to run `clearInterval()`, `window.removeEventListener()`, and disconnect from the server, respectively.
Here's the syntax for returning a cleanup function from the `useEffect` hook:
```js
useEffect(() => {
// Your side effect logic here
return () => {
// Cleanup logic here (optional)
};
}, [dependencies]);
```
For instance, if you add a scroll event listener, you can clean it up by removing it in your cleanup function:
```js
useEffect(() => {
const handleScroll = () => {
// Handle scroll logic
};
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
```
# --questions--
@@ -18,7 +133,7 @@ What is considered an effect in React?
## --answers--
Any update to the components state.
Any update to the component's state.
### --feedback--
@@ -26,7 +141,7 @@ Effects involve actions React doesn't control during rendering.
---
Operations outside the rendering process that React doesnt manage.
Operations outside the rendering process that React doesn't manage.
---
@@ -50,7 +165,7 @@ Effects involve actions React doesn't control during rendering.
## --text--
What determines how side effects run in a React app based on the dependency array?
What determines how side effects run in a React app?
## --answers--
@@ -70,7 +185,7 @@ The behavior of the effect depends on the contents of the dependency array.
---
The dependency array determines when effects run, based on its contents.
The dependency array determines when effects run.
---

View File

@@ -2,13 +2,145 @@
id: 67d1ec87b34cee1d9219f7e9
title: How Can You Create Custom Hooks in React?
challengeType: 11
videoId: nVAaxZ34khk
videoId: r9MI-2J01PY
dashedName: how-can-you-create-custom-hooks-in-react
---
# --description--
Watch the lecture video and answer the questions below.
Watch the video or read the transcript and answer the questions below.
# --transcript--
How can you create custom hooks in React?
React provides many built-in hooks that let you implement different features in your projects. These include `useState`, `useEffect`, `useContext`, and others.
But sometimes, you'll need to add a feature that none of the built-in hooks can help with. Fortunately, you can create your own custom hooks in React.
Custom hooks are not as complicated as they might seem. They're just reusable functions that let you share logic across multiple components. That means reusability is another reason why you would want to build your own hook.
With a custom hook, you can extract logic away from any components that use them, like data fetching, state management, toggling, side effects like checking for the online or offline status of users, and so on.
You can then import the hook to use in any component, so you can focus on rendering and presentation within those components. That means fewer repetitions and less duplication, which means fewer places to make changes when you want to make any updates.
Now, let's take a look at how you can make your own custom hook.
In React, all built-in hooks start with the word `use`, so your custom hook should follow the same convention. Your custom hook's name should also clearly communicate what it does.
So, if your custom hook…
- fetches data, you can call it `useFetch`
- toggles something on and off, you can call it `useToggle`
- or if it implements debouncing, `useDebounce` is a good name
Let's say you want to build a custom hook to add debouncing to your app.
Debouncing is a programming technique that limits how often a function runs. It works by waiting until a user stops performing an action for a specified period of time before executing the function. For example, in a search box, instead of making an API call for every keystroke, debouncing waits until the user pauses typing for, say, 500 milliseconds.
To create a debouncing custom hook, you first need to create a `useDebounce.jsx` or `useDebounce.js` file. Conventionally, files for any custom hooks you create are saved to a `hooks` folder.
You can use some built-in hooks within your own custom hook. For debouncing, you need the `useState` and `useEffect` hooks, so import them at the top of your file:
```js
import { useState, useEffect } from "react";
```
Next, create a `useDebounce` function that takes `value` and `delay` as parameters. `value` is the resource you want to wait for, and `delay` is the period of time you want to wait for. Since you want to wait for some period of time, the `setTimeout` and `clearTimeout` functions would be useful:
```js
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}
export { useDebounce };
```
The `debouncedValue` state holds and returns the delayed value, which only updates after the specified timeout period.
`useEffect` is where the magic really happens. If you recall from the previous lecture, anything that exists outside the React rendering cycle, like setting and clearing a timer, is a side effect, and you should use the `useEffect` hook to handle them.
Within the `useEffect` hook here, you use `setTimeout` to set the `debouncedValue`. You then return a cleanup function that uses `clearTimeout` to clear the previous timeout whenever `value` or `delay` changes, or the component unmounts.
To use this hook, we've prepared a `footballers` array to filter through with a simple search bar:
```js
const footballers = [
'Lionel Messi', 'Cristiano Ronaldo', 'Neymar Jr',
'Kylian Mbappe', 'Mohamed Salah', 'Sadio Mane',
'Kevin De Bruyne', 'Robert Lewandowski', 'Harry Kane',
'Sergio Ramos', 'Virgil van Dijk', 'Alisson Becker',
'Joshua Kimmich', 'Manuel Neuer', 'Karim Benzema',
'Thibaut Courtois', 'Eden Hazard', 'Raheem Sterling',
'Bruno Fernandes', 'Trent Alexander-Arnold', 'Son Heung-min',
'Pierre-Emerick Aubameyang','Sergio Aguero', 'Luis Suarez',
'Luka Modric', 'Casemiro', 'Frenkie de Jong', 'Gerard Pique',
'Marc-Andre ter Stegen', 'Keylor Navas', 'Angel Di Maria',
"N'Golo Kante", 'Kai Havertz', 'Timo Werner', 'Hakim Ziyech',
'Christian Pulisic', 'Mason Mount', 'Olivier Giroud', 'Tammy Abraham',
'Kepa Arrizabalaga', 'Ben Chilwell', 'Thiago Silva', 'Kurt Zouma',
'John Terry', 'Didier Drogba', 'Frank Lampard', 'Ashley Cole', 'Petr Cech',
];
export default footballers;
```
And here's a `FootballerSearch` component that uses the `useDebounce` hook to delay searching for 1 second after the user stops typing:
```js
import { useState, useEffect } from "react";
import { useDebounce } from "./hooks/useDebounce";
import footballers from "./footballers";
const FootballerSearch = () => {
const [query, setQuery] = useState("");
const debouncedQuery = useDebounce(query, 1000); // Start searching 1 second after the user stops typing
useEffect(() => {
if (debouncedQuery) {
const results = footballers.filter((footballer) =>
footballer.toLowerCase().includes(debouncedQuery.toLowerCase()),
);
console.log("Search results:", results);
} else {
console.log("Search results: []");
}
}, [debouncedQuery]);
return (
<>
<h1 style={{ textAlign: "center" }}>Footballer Search App</h1>
<div style={{ textAlign: "center" }}>
<input
style={{ padding: "0.5rem", width: "30%" }}
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search for a footballer..."
/>
</div>
</>
);
};
export default FootballerSearch;
```
As you can see, the `debouncedQuery` variable is what initializes the `useDebounce` hook with the query state (what the user types), and the delay for 1,000 milliseconds, or 1 second. The search itself is handled inside the `useEffect` hook, and search results are logged to the console.
# --questions--