Skip to content

Commit f8c5a86

Browse files
scissorsneedfoodtooDario-DCzairahira
authored
feat: add react debugging video ids and transcripts (freeCodeCamp#59632)
Co-authored-by: Dario-DC <105294544+Dario-DC@users.noreply.github.com> Co-authored-by: Zaira <33151350+zairahira@users.noreply.github.com>
1 parent f0ba844 commit f8c5a86

4 files changed

Lines changed: 532 additions & 16 deletions

File tree

curriculum/challenges/english/25-front-end-development/lecture-react-strategies-and-debugging/67d1ad82cff954a854bcbcaa.md

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,118 @@
22
id: 67d1ad82cff954a854bcbcaa
33
title: What Is Prop Drilling?
44
challengeType: 11
5-
videoId: nVAaxZ34khk
5+
videoId: 83LkOesFkWI
66
dashedName: what-is-prop-drilling
77
---
88

99
# --description--
1010

11-
Watch the video lecture and answer the questions below.
11+
Watch the video or read the transcript and answer the questions below.
12+
13+
# --transcript--
14+
15+
What is prop drilling?
16+
17+
Prop drilling is the most basic approach to state management in React applications. It looks simple, but can get messy quickly, and is very hard to scale.
18+
19+
Let's look at what prop drilling is, why it's a problem, and a good replacement for it as an application grows.
20+
21+
Prop drilling is the process of passing props from a parent component to deeply nested child components, even when some of the child components don't need the props.
22+
23+
For example, say you have three components named `Parent`, `Child`, and `Grandchild`. If you want to use some data in the `Grandchild` component, but it's in the `Parent` component, you'd need to pass it from the `Parent` to the `Child` component, then from the `Child` to the `Grandchild` component.
24+
25+
Or if the data is even further up the chain, the data might have to be passed to the `Parent` component, too.
26+
27+
Here, the data I want to display is the string `Hello, Prop Drilling!`. It's assigned to the `greeting` variable in the root `App` component:
28+
29+
```jsx
30+
import "./App.css";
31+
import Parent from "./Parent";
32+
33+
function App() {
34+
const greeting = "Hello, Prop Drilling!";
35+
36+
return <Parent greeting={greeting} />;
37+
}
38+
39+
export default App;
40+
```
41+
42+
You can see the `Parent` component is also receiving the `greeting` variable as the value of a `greeting` prop. Here's the `Parent` component passing it into the `Child` component as the value of another `greeting` prop in the `Child`:
43+
44+
```jsx
45+
import Child from "./Child";
46+
47+
const Parent = ({ greeting }) => {
48+
return <Child greeting={greeting} />;
49+
};
50+
51+
export default Parent;
52+
```
53+
54+
And here's the `Child` component that passes it to the `Grandchild` component:
55+
56+
```jsx
57+
import Grandchild from "./Grandchild";
58+
59+
const Child = ({ greeting }) => {
60+
return <Grandchild greeting={greeting} />;
61+
};
62+
63+
export default Child;
64+
```
65+
66+
And finally the `Grandchild` component receives the greeting and uses it as the content of an `h1` element:
67+
68+
```jsx
69+
const Grandchild = ({ greeting }) => {
70+
return <h1>{greeting}</h1>;
71+
};
72+
73+
export default Grandchild;
74+
```
75+
76+
In the browser, you'll see a page with a single `h1` element that has the text `Hello, Prop Drilling!`.
77+
78+
At first, prop drilling might not seem like such a big deal. But as your app grows, it gets harder to understand, debug, and maintain.
79+
80+
If you need to pass props around, try to keep them all in a single parent component. This approach of centralizing all necessary data is called the "single source of truth".
81+
82+
For instance, say you want to add a new `response` to go with your `greeting`, and that you want to use both of them in the `Grandchild` component. Since `greeting` is already in the `App` component, it makes sense to put `response` there, too, and pass both of them down the chain:
83+
84+
```jsx
85+
function App() {
86+
const greeting = "Hello, Prop Drilling!";
87+
const response = "I'm not here to play!";
88+
89+
return <Parent greeting={greeting} response={response} />;
90+
}
91+
92+
const Parent = ({ greeting, response }) => {
93+
return <Child greeting={greeting} response={response} />;
94+
};
95+
96+
const Child = ({ greeting, response }) => {
97+
return <Grandchild greeting={greeting} response={response} />;
98+
};
99+
100+
const Grandchild = ({ greeting, response }) => {
101+
return (
102+
<>
103+
<h1>{greeting}</h1>
104+
<h2>{response}</h2>
105+
</>
106+
);
107+
};
108+
109+
export default App;
110+
```
111+
112+
In the browser, you'll see a page with an `h1` element that has the text `Hello, Prop Drilling!` and an `h2` element that has the text `I'm not here to play!`.
113+
114+
To avoid prop drilling, especially in large, complex applications, consider using the Context API or state management libraries like Redux and Redux Toolkit, Zustand, Recoil, and others.
115+
116+
You'll learn more about these in the coming lectures.
12117

13118
# --questions--
14119

curriculum/challenges/english/25-front-end-development/lecture-react-strategies-and-debugging/67d2f5b78609f97400923f7f.md

Lines changed: 196 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,199 @@
22
id: 67d2f5b78609f97400923f7f
33
title: What Are State Management Libraries, and When Should You Use Them?
44
challengeType: 11
5-
videoId: nVAaxZ34khk
5+
videoId: 9GBjI8LDauU
66
dashedName: what-are-state-management-libraries-and-when-should-you-use-them
77
---
88

99
# --description--
1010

11-
Watch the lecture video and answer the questions below.
11+
Watch the video or read the transcript and answer the questions below.
12+
13+
# --transcript--
14+
15+
What are state management libraries, and when should you use them?
16+
17+
As your app grows, managing how data flows between components can become complex.
18+
19+
When starting out, React's `useState` hook might be sufficient, but as you add features, you might encounter issues with:
20+
21+
- Passing props through components that don't need them, also known as prop drilling
22+
- Keeping data in sync across different parts of your app
23+
- Handling complex updates that affect multiple components simultaneously
24+
25+
These and other challenges may arise, which can lead to a codebase that's harder to maintain, debug, and test. That's where state management libraries come in – they provide a centralized place where components can get or update the data they need.
26+
27+
Let's take a look at a few different state management options you have, and when to use them.
28+
29+
The Context API is a state manager built into React that lets you share state across components without using a third-party library. It's a well-established upgrade over the `useState` hook, so it is perfect for cases like theme toggling or user authentication status.
30+
31+
However, the Context API does not handle frequent updates well, and can cause unnecessary re-renders, making it less suitable for complex state needs in applications like eCommerce and social media platforms. 
32+
33+
Here's a counter component that demonstrates the basic usage of the Context API:
34+
35+
```jsx
36+
import { useState, createContext } from 'react';
37+
38+
const CounterContext = createContext();
39+
40+
const CounterProvider = ({ children }) => {
41+
const [count, setCount] = useState(0);
42+
43+
return (
44+
<CounterContext.Provider value={{ count, setCount }}>
45+
{children}
46+
</CounterContext.Provider>
47+
);
48+
};
49+
50+
export { CounterContext, CounterProvider };
51+
```
52+
53+
This code creates a context and a provider to share a `count` state across the application.
54+
55+
`CounterProvider` uses the `useState` hook to initialize and manage the `count` state and its setter. Both are then passed into child components through the `Provider`.
56+
57+
So, when you wrap your whole app with the `CounterProvider`, the `count` state is available everywhere in your application.
58+
59+
Here's how you can wrap `CounterProvider` around your application:
60+
61+
```jsx
62+
import { CounterProvider } from './context/CounterContext';
63+
64+
function App() {
65+
return (
66+
<CounterProvider>
67+
{/* App components */}
68+
</CounterProvider>
69+
);
70+
}
71+
72+
export default App;
73+
```
74+
75+
And here's how you can use the `count` state:
76+
77+
```jsx
78+
import React, { useContext } from 'react';
79+
import { CounterContext } from '../context/CounterContext';
80+
81+
const Counter = () => {
82+
const { count, setCount } = useContext(CounterContext);
83+
84+
return (
85+
<>
86+
<div style={{ textAlign: 'center' }}>
87+
<h1>Context API Counter</h1>
88+
<button style={{ marginRight: '5px' }} onClick={() => setCount(count - 1)}>
89+
Decrease
90+
</button>
91+
<span>{count}</span>
92+
<button style={{ marginLeft: '5px' }} onClick={() => setCount(count + 1)}>
93+
Increase
94+
</button>
95+
</div>
96+
</>
97+
);
98+
};
99+
100+
export default Counter;
101+
```
102+
103+
As you can see, the `count` and its setter function, `setCount`, are initialized through the `useContext` function.
104+
105+
The current `count` state is then displayed, and `setCount` is used to increase and decrease the `count` state when the user clicks the decrement and increment buttons respectively.
106+
107+
Another popular state management library is Redux, which is one of the most popular state management libraries to use with React. It's been around for a long time, and is ideal for larger applications like eCommerce and social media platforms, forums, and so on.
108+
109+
Redux handles state management by providing a central store and strict control over state updates. It uses a predictable pattern with actions, reducers, and middleware.
110+
111+
Actions are payloads of information that send data from your application to the Redux store, often triggered by user interactions.
112+
113+
Reducers are functions that specify how the state should change in response to those actions, ensuring the state is updated in an immutable way.
114+
115+
Middleware, on the other hand, acts as a bridge between the action dispatching and the reducer, allowing you to extend Redux's functionality (for example, logging, handling async operations) without modifying the core flow.
116+
117+
The most common complaint about Redux is with all the boilerplate code you need to get started. In response, the Redux team introduced "Redux Toolkit" and "RTK Query", which simplify the setup process quite a bit.
118+
119+
You typically define both actions and reducers in a single file using the `createSlice()` function. It's common to name the file so it ends with the word `Slice`, for example, `productSlice`, `userSlice`, `counterSlice`, and so on.
120+
121+
Here's a `counterSlice` file to show you the basics:
122+
123+
```jsx
124+
import { createSlice } from '@reduxjs/toolkit';
125+
126+
const counterSlice = createSlice({
127+
name: 'counter',
128+
129+
initialState: { count: 0 },
130+
131+
reducers: {
132+
increment: (state) => {
133+
state.count += 1;
134+
},
135+
decrement: (state) => {
136+
state.count -= 1;
137+
},
138+
},
139+
});
140+
141+
export const { increment, decrement } = counterSlice.actions;
142+
143+
export default counterSlice.reducer;
144+
```
145+
146+
From here, you then need to wrap the entire app with the `Provider`, select a piece of state from the slice with `useSelector()`, then use `useDispatch()` to make the state active.
147+
148+
Another option to consider is Zustand.
149+
150+
Zustand is a lightweight state management library with a simple API. It is based on hooks, so there's less boilerplate compared to Redux, making it easier and quicker to set up.
151+
152+
Zustand is ideal for small to medium-scale applications. It works by using a `useStore` hook to access access state directly in components and pages. This lets you modify and access data without needing actions, reducers, or a provider.
153+
154+
Here's a `useCounterStore` that implements another counter functionality:
155+
156+
```jsx
157+
import { create } from 'zustand';
158+
159+
const useCounterStore = create((set) => ({
160+
count: 0,
161+
increment: () => set((state) => ({ count: state.count + 1 })),
162+
decrement: () => set((state) => ({ count: state.count - 1 })),
163+
}));
164+
165+
export default useCounterStore;
166+
```
167+
168+
And here's how to initialize and use the states in your app:
169+
170+
```jsx
171+
// Import the useCounterStore (it's just a hook)
172+
import useCounterStore from '../useCounterStore';
173+
174+
const Counter = () => {
175+
// Initialize the states with the useCounterStore hook
176+
const { count, increment, decrement } = useCounterStore();
177+
178+
return (
179+
<>
180+
<div style={{ textAlign: 'center' }}>
181+
<h1>Zustand Counter</h1>
182+
<button style={{ marginRight: '5px' }} onClick={() => decrement()}>
183+
Decrease
184+
</button>
185+
<span>{count}</span>
186+
<button style={{ marginLeft: '5px' }} onClick={() => increment()}>
187+
Increase
188+
</button>
189+
</div>
190+
</>
191+
);
192+
};
193+
194+
export default Counter;
195+
```
196+
197+
Even though the frontend ecosystem is constantly evolving and new state management libraries regularly emerge, the ones we've discussed are widely used in the industry.
12198

13199
# --questions--
14200

@@ -86,35 +272,35 @@ Axios
86272

87273
## --text--
88274

89-
What is the popular complaint about Redux, and how was it addressed?
275+
What was a common complaint about Redux, and how was it addressed?
90276

91277
## --answers--
92278

93-
Limited browser support; addressed by creating polyfills.
279+
It had limited browser support, which was addressed by creating polyfills.
94280

95281
### --feedback--
96282

97-
Think about improvements made to reduce setup complexity.
283+
Think about the improvements that were made to reduce setup complexity.
98284

99285
---
100286

101-
Performance issues; addressed by optimizing middleware.
287+
It had performance issues, which were addressed by optimizing its middleware.
102288

103289
### --feedback--
104290

105-
Think about improvements made to reduce setup complexity.
291+
Think about the improvements that were made to reduce setup complexity.
106292

107293
---
108294

109-
Complexity of boilerplate code; addressed with Redux Toolkit and RTK Query.
295+
It required a lot of complex boilerplate code, which was addressed by Redux Toolkit and RTK Query.
110296

111297
---
112298

113-
Lack of documentation; addressed by adding more examples.
299+
There was a lack of documentation, which was addressed by adding more examples.
114300

115301
### --feedback--
116302

117-
Think about improvements made to reduce setup complexity.
303+
Think about the improvements that were made to reduce setup complexity.
118304

119305
## --video-solution--
120306

0 commit comments

Comments
 (0)