Count: {count}
40 |Value: {value}
31 |Expensive Result: {expensiveResult}
32 |Count: {count}
36 | 37 |Typed text: {text}
59 |Count: {count}
30 | 31 |useEffect
. According to the React documentation, error boundaries do not handle errors in:
13 | - Event handlers
14 | - Asynchronous code (e.g., setTimeout or requestAnimationFrame callbacks)
15 | - Server-side rendering
16 | - Errors thrown in the error boundary itself (rather than its children)
17 |
18 | So basically, error boundaries only handle errors in the parts of our code that involve React.
19 |
20 | To create an error boundary, we simply have to create a class component and define a state variable for determining whether the error boundary has caught an error. Our class component should also have at least three methods:
21 |
22 | - A static method called getDerivedStateFromError, which is used to update the error boundary’s state
23 | - A componentDidCatch lifecycle method for performing operations when our error boundaries catch an error, such as logging to an error logging service
24 | - A render method for rendering our error boundary’s child or the fallback UI in case of an error
25 |
26 | Here’s an example (taken from the React docs) of what our simple error boundary should look like:
27 |
28 | ```jsx
29 | class ErrorBoundary extends React.Component {
30 | constructor(props) {
31 | super(props);
32 | this.state = { hasError: false };
33 | }
34 |
35 | static getDerivedStateFromError(error) {
36 | // Update state so the next render will show the fallback UI.
37 | return { hasError: true };
38 | }
39 |
40 | componentDidCatch(error, errorInfo) {
41 | // You can also log the error to an error reporting service
42 | logErrorToMyService(error, errorInfo);
43 | }
44 |
45 | render() {
46 | if (this.state.hasError) {
47 | // You can render any custom fallback UI
48 | return ErrorBoundary
component and pass in some extra props to customize our error boundary’s behavior.
60 |
61 | ## ErrorBoundary component 🔴
62 |
63 | The ErrorBoundary component is the main component available in react-error-boundary. It allows us to implement the typical React error boundary with less code.
64 |
65 | Here’s a very basic use case of ErrorBoundary
:
66 |
67 | ```jsx
68 | function App(){
69 | ...
70 | return (
71 | ErrorBoundary
component and pass in our fallback component to the FallbackComponent
prop so that if there’s an error (that can be caught and handled by react-error-boundary), our fallback component will be rendered; otherwise, our component will be rendered.
90 |
91 | We also have the fallbackRender
prop, which is a render prop-based API for specifying our fallback component in an inline manner. Here’s the above code block using the fallbackRender
prop:
92 |
93 | ```jsx
94 | function App(){
95 | ...
96 | return (
97 | Something went wrong:
141 |{error.message}142 |
{componentStack}143 | 144 |
App
component renders a Bomb
component that throws an error or an error-safe component. Reset keys were also passed to the error boundary component. These reset keys determine whether the error boundary’s internal state will be reset. If one of the reset keys change during renders, the error boundary’s internal state will be reset.
170 |
171 | On the other hand, calling the resetComponent
function triggers the onResethandler
of our ErrorBoundary
component, where we set our explode state value to false. This causes our App component to render an error-safe component.
172 |
173 | We also have the onResetKeysChange
handler, which is triggered when the value of the reset keys change, causing a reset of the error boundary’s internal state.
174 |
175 | - ## ErrorBoundary component 🟢
176 |
177 | react-error-boundary enables React developers to reduce the amount of code that must be written and expand their error boundary capabilities to catch other forms of errors that wouldn’t otherwise be identified by regular error boundaries. Learn more about react-error-boundary on GitHub.
178 |
--------------------------------------------------------------------------------
/docs/immutability.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: Immutability
3 | title: Immutability
4 | sidebar_position: 6
5 | ---
6 |
7 | # Immutability in React 📌
8 |
9 | One of the first things you learn when you begin working with React is that you shouldn’t mutate or modify a list:
10 |
11 | ```jsx
12 | // This is bad, push modifies the original array
13 | items.push(newItem);
14 | // This is good, concat doesn’t modify the original array
15 | const newItems = items.concat([newItem]);
16 | ```
17 |
18 | Despite popular belief, there’s actually nothing wrong with mutating objects. In certain situations, like concurrency, it can become a problem, however, mutating objects is the easiest development approach. Just like most things in programming, it’s a trade-off.
19 |
20 | Functional programming and concepts like immutability are popular topics. But in the case of React, immutability isn’t just fashionable, it has some real benefits. In this article, we’ll explore immutability in React, covering what it is and how it works. Let’s get started!
21 |
22 | ## What is immutability? 🟠
23 |
24 | If something is immutable, we cannot change its value or state. Although this may seem like a simple concept, as usual, the devil is in the details.
25 |
26 | You can find immutable types in JavaScript itself; the String value type is a good example. If you define a string as follows, you cannot change a character of the string directly:
27 |
28 | ```jsx
29 | var str = 'abc';
30 | ```
31 |
32 | In JavaScript, strings are not arrays, so you can define one as follows:
33 |
34 | ```jsx
35 | str[2] = 'd';
36 | ```
37 |
38 | Defining a string using the method below assigns a different string to str:
39 |
40 | ```javascript
41 | str = 'abd';
42 | ```
43 |
44 | You can even define the str reference as a constant:
45 |
46 | ```javascript
47 | const str = 'abc'
48 | ```
49 |
50 | Therefore, assigning a new string generates an error. However, this doesn’t relate to immutability. If you want to modify the string value, you have to use manipulation methods like replace()
, toUpperCase()
, or trim()
. All of these methods return new strings; they don’t modify the original one.
51 |
52 | ## Value type 🟣
53 |
54 | It’s important to pay attention to the value type. String values are immutable, but string objects are not.
55 |
56 | ```javascript
57 | const str = new String("abc");
58 | str.myNewProperty = "some value";
59 |
60 | alert(str.myNewProperty);
61 |
62 | str.myNewProperty = "a new value";
63 |
64 | alert(str.myNewProperty);
65 | ```
66 |
67 | Strings are immutable. The last example creates an object with the String() constructor that wraps the immutable string value. You can add new properties to this wrapper because it’s an object, and it’s not frozen. This example leads us to a concept that is important to understand; the difference between reference and value equality.
68 |
69 |
70 | ## Reference equality vs value equality
71 |
72 | With reference equality, you compare object references with either the ===
and !==
operators or the ==
and !=
operators. If the references point to the same object, they are considered equal:
73 |
74 | ```javascript
75 | var str1 = ‘abc’;
76 | var str2 = str1;
77 | str1 === str2 // true
78 | ```
79 |
80 | In the example above, both the str1
and str2
references are equal because they point to the same object, 'abc'
:
81 |
82 | 
83 |
84 | Two references are also equal when they refer to the same value if this value is immutable:
85 |
86 | ```javascript
87 | var str1 = ‘abc’;
88 | var str2 = ‘abc’;
89 | str1 === str2 // true
90 | var n1 = 1;
91 | var n2 = 1;
92 | n1 === n2 // also true
93 | ```
94 |
95 | 
96 |
97 | But, when talking about objects, this doesn’t hold true anymore:
98 |
99 | ```javascript
100 | var str1 = new String(‘abc’);
101 | var str2 = new String(‘abc’);
102 | str1 === str2 // false
103 | var arr1 = [];
104 | var arr2 = [];
105 | arr1 === arr2 // false
106 | ```
107 |
108 | In each of these cases, two different objects are created, and therefore, their references are not equal:
109 | 
110 |
111 | If you want to check if two objects contain the same value, you have to use value equality, where you compare the values of the properties of the object.
112 |
113 | In JavaScript, there’s no direct way to perform value equality on objects and arrays. If you’re working with string objects, you can use the valueOf
or trim
methods, which return a string value:
114 |
115 | ```javascript
116 | var str1 = new String(‘abc’);
117 | var str2 = new String(‘abc’);
118 | str1.valueOf() === str2.valueOf() // true
119 | str1.trim() === str2.trim() // true
120 | ```
121 |
122 | For any other type of object, you either have to implement your own equals method or use a third-party library. It’s easier to test if two objects are equal if they are immutable. React takes advantage of this concept to make some performance optimizations; let’s explore these in detail.
123 |
124 | ## Immutability performance optimizations in React 🔵
125 |
126 | React maintains an internal representation of the UI, called the virtual DOM. When either a property or the state of a component changes, the virtual DOM is updated to reflect those changes. Manipulating the virtual DOM is easier and faster because nothing is changed in the UI. Then, React compares the virtual DOM with the version before the update to know what changed, known as the reconciliation process.
127 |
128 | Therefore, only the elements that changed are updated in the real DOM. However, sometimes, parts of the DOM are re-rendered even when they didn’t change. In this case, they’re a side effect of other parts that do change. You could implement the shouldComponentUpdate()
function to check if the properties or the state really changed, then return true
to let React perform the update:
129 |
130 | ```jsx
131 | class MyComponent extends Component {
132 | // ...
133 | shouldComponentUpdate(nextProps, nextState) {
134 | if (this.props.myProp !== nextProps.color) {
135 | return true;
136 | }
137 | return false;
138 | }
139 | // ...
140 | }
141 | ```
142 |
143 | If the properties and state of the component are immutable objects or values, you can check to see if they changed with a simple equality operator.
144 |
145 | From this perspective, immutability removes complexity because sometimes it is hard to know exactly what changed. For example, think about deep fields:
146 |
147 | ```javascript
148 | myPackage.sender.address.country.id = 1;
149 | ```
150 |
151 | How can you efficiently track which nested object changed? Think about arrays. For two arrays of the same size, the only way to know if they are equal is by comparing each element, which is a costly operation for large arrays.
152 |
153 | The most simple solution is to use immutable objects. If the object needs to be updated, you have to create a new object with the new value since the original one is immutable and cannot be changed. You can use reference equality to know that it changed.
154 |
155 | The React documentation also suggests treating state as if it were immutable. Directly manipulating the state nullifies React’s state management, resulting in performance issues. The React useState Hook plays a vital role in performance optimization, allowing you to avoid directly manipulating the state in functional components.
156 |
157 | To some people, this concept may seem a little inconsistent or opposed to the ideas of performance and simplicity. So, let’s review the options you have to create new objects and implement immutability.
158 |
159 | ## Implementing immutability in React 🟠
160 |
161 | In most real world applications, your state and properties will be objects and arrays. JavaScript provides some methods to create new versions of them.
162 |
163 | ### Object.assign
164 |
165 | Instead of manually creating an object with the new property, you can use Object.assign
to avoid defining the unmodified properties:
166 |
167 | ```javascript
168 | const modifyShirt = (shirt, newColor, newSize) => {
169 | return {
170 | id: shirt.id,
171 | desc: shirt.desc,
172 | color: newColor,
173 | size: newSize
174 | };
175 | }
176 |
177 |
178 | const modifyShirt = (shirt, newColor, newSize) => {
179 | return Object.assign( {}, shirt, {
180 | color: newColor,
181 | size: newSize
182 | });
183 | }
184 | ```
185 |
186 | Object.assign
will copy all of the properties of the objects passed as parameters, starting from the second parameter to the object specified in the first parameter.
187 |
188 | ### Spread operator
189 |
190 | You can use the spread operator with the same effect; the difference is that Object.assign() uses setter methods to assign new values, while the spread operator doesn’t:
191 |
192 | ```javascript
193 | const modifyShirt = (shirt, newColor, newSize) => {
194 | return {
195 | ...shirt,
196 | color: newColor,
197 | size: newSize
198 | };
199 | }
200 | ```
201 |
202 | You can also use the spread operator to create arrays with new values:
203 |
204 | ```javascript
205 | const addValue = (arr) => {
206 | return [...arr, 1];
207 | };
208 | ```
209 |
210 | ### Concat and Slice methods
211 |
212 | Alternately, you can use methods like concat or slice, which return a new array without modifying the original one:
213 |
214 | ```javascript
215 | const addValue = (arr) => {
216 | return arr.concat([1]);
217 | };
218 | const removeValue = (arr, index) => {
219 | return arr.slice(0, index)
220 | .concat(
221 | arr.slice(index+1)
222 | );
223 | };
224 | ```
225 |
226 | In this gist, you’ll see how to combine the spread operator with these methods to avoid mutating arrays while performing common operations.
227 |
228 | However, there are two main drawbacks to using these native approaches. For one, they copy properties or elements from one object or array to another, which could be a slow operation for larger objects and arrays. In addition, objects and arrays are mutable by default. There’s nothing that enforces immutability. You have to remember to use one of these methods.
229 |
230 | For these reasons, it’s better to use an external library that handles immutability.
231 |
232 | ## Immutability libraries 🟣
233 | The React team recommends Immutable.js and immutability-helper, but you can find many libraries with similar functionality. There are three main types:
234 | - Libraries that work with specialized data structures
235 | - Libraries that work by freezing objects
236 | - Libraries with helper functions that perform immutable operations
237 | Most of these libraries work with persistent data structures.
238 |
239 | ## Benefits of immutability 🔵
240 | Overall, immutability improves your app’s performance and promotes easy debugging. It allows for the simple and inexpensive implementation of sophisticated techniques for detecting changes, and it ensures that the computationally expensive process of updating the DOM is performed only when absolutely necessary.
241 |
242 | ## Disadvantages of immutability 🟢
243 |
244 | However, immutability is not without its own problems. As I mentioned before, when working with objects and arrays, you either have to remember to use methods than enforce immutability or use third-party libraries.
245 |
246 | Many of these libraries work with their own data types. Although they provide compatible APIs and ways to convert these types to native JavaScript types, you have to be careful when designing your application to avoid high degrees of coupling or harm performance with methods like toJs().
247 |
248 | If the library doesn’t implement new data structures, for example, libraries that work by freezing objects, there won’t be any of the benefits of structural sharing. Most likely, objects will be copied when updated, and performance will suffer in some cases.
249 |
250 | Additionally, implementing immutability concepts with larger teams can be time-consuming because individual developers must be disciplined, especially when using third-party libraries with steep learning curves. You also have to consider the learning curve associated with these libraries.
251 |
252 |
253 | ## Conclusion 🟠
254 | Understanding immutability is essential for React developers. An immutable value or object cannot be changed, so every update creates new value, leaving the old one untouched. For example, if your application state is immutable, you can save all the state objects in a single store to easily implement functionality to undo and redo.
255 |
256 | Version control systems like Git work in a similar way. Redux is also based on that principle. However, the focus on Redux is more on the side of pure functions and snapshots of the application state.
257 |
258 | Immutability has other advantages like avoiding unexpected side effects or reducing coupling, but it also has disadvantages. Remember, as with many things in programming, it’s a trade-off.
259 |
--------------------------------------------------------------------------------
/docs/introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: introduction
3 | title: Introduction
4 | sidebar_position: 1
5 | ---
6 |
7 | # Introduction
8 |
9 | Welcome to my ReactJS notebook repository! This repository is a collection of notes and examples on learning ReactJS. It covers the basics of the library and progresses to more advanced topics. The goal of this repository is to provide a useful resource for anyone looking to learn ReactJS, as well as a personal notebook for tracking my own progress📊. If you find this repository helpful, please consider giving it a star to show your support. Thank you!
10 |
11 | You can use this repository as a starting point and edit it to fit your needs.
--------------------------------------------------------------------------------
/docs/proptypes.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: proptypes
3 | title: PropTypes
4 | sidebar_position: 7
5 | ---
6 |
7 | # PropTypes in React 📊
8 |
9 | PropTypes are a good first line defense when it comes to debugging your apps. But before getting into detail about PropTypes, we have to understand the concept of props.
10 |
11 |
12 | Props are the read-only properties that are shared between components to give the unidirectional flow of React a dynamic touch. They're mainly shared from the parent component to the child component, but the reverse is also possible (though not recommended).
13 |
14 | ## What are PropTypes? 🟢
15 | PropTypes are simply a mechanism that ensures that the passed value is of the correct datatype. This makes sure that we don’t receive an error at the very end of our app by the console which might not be easy to deal with.
16 |
17 | I don't recommend using them in short apps like projects for self-practice but it's totally up to you. For larger projects like for a client, it's often a wise choice and a good practice to use them.
18 |
19 | There are many different types of PropTypes and all of them have their unique ES6 classes which we can use. We will discuss every type in this article.
20 |
21 | ## How to use PropTypes? 🟣
22 | Before the release of React 15.5.0, PropTypes were available in the React package, but now we have to add the prop-types library in our project.
23 |
24 | We can do so by running the following command in our terminal:
25 |
26 | ```javascript
27 | npm install prop-types --save
28 | ```
29 |
30 | We can use PropTypes to validate any data we are receiving from props. But before using it we will have to import it as always in our app:
31 |
32 | ```jsx
33 | import PropTypes from 'prop-types';
34 | ```
35 | They are often used after the component ends and starts with the name of the component as shown:
36 |
37 | ```jsx
38 | import React from 'react';
39 | import { PropTypes } from "prop-types";
40 |
41 | const Count = (props) => {
42 | return (
43 | <>
44 | .........
45 | >
46 | )
47 | };
48 |
49 | Count.propTypes = {
50 | // key is the name of the prop and
51 | // value is the PropType
52 | }
53 | export default Count;
54 | ```
55 |
56 | PropTypes are also objects with a key and a value pair where the ‘key’ is the name of the prop while the value represents the type or class by which they are defined.
57 |
58 | Since defining PropTypes on a component does not depend on the component implementation, we will be leaving out the code for the component itself in all the following examples. The code above can be simplified to the following:
59 |
60 |
61 | ```jsx
62 | Count.propTypes = {
63 | // Put props here
64 | }
65 | ```
66 |
67 | Let's discuss how many types of PropTypes are there before understanding them with an example.
68 |
69 | ## Basic Types of PropTypes 🔵
70 |
71 |
72 | The most basic way we can check a prop's type is by checking if it falls under the category of primitive types in JavaScript, such as a boolean, string, object, and so on.
73 |
74 | Below is the list of all data types that are considered primitive or the basic ones with their classes that we can use to check props.
75 | 
76 |
77 | Below is an example that shows us how to use these PropTypes for type checking in our app. As we discussed already, they are defined as objects with a key and a value pair where the key is the name of the object while value contains the classes which will be used for type checking.
78 |
79 | ```jsx
80 | Count.propTypes = {
81 | name: PropTypes.string,
82 | age: PropTypes.number,
83 | address: PropTypes.object,
84 | friends: PropTypes.array,
85 | };
86 | ```
87 |
88 | In the above code, the name prop is expected to have a value which is a string, age is a number, address is an object, and friends is an array. If any value other than this has been used for the same props as a value, it will show an error in the console like this:
89 | 
90 |
91 | We can chain any of the above with isRequired
to make sure a warning is shown if the prop isn't provided.
92 |
93 | ```jsx
94 | Count.propTypes = {
95 | basicObject: PropTypes.object,
96 | numbers: PropTypes.objectOf(PropTypes.numbers),
97 | messages: PropTypes.instanceOf(Message),
98 | contactList: PropTypes.shape({
99 | name: PropTypes.string.isRequired,
100 | phone: PropTypes.string.isRequired,
101 | }),
102 | };
103 | ```
104 |
105 | ## Conclusion 🟢
106 |
107 | PropTypes are a great way to catch errors at run time and act as the first line of defense for your applications. They're not as type-safe as TypeScript but they're much easier to set up and work with.
--------------------------------------------------------------------------------
/docs/react-children.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: react-children
3 | title: Children
4 | sidebar_position: 10
5 | ---
6 |
7 | # Children Props 👻
8 |
9 | The most obvious and common prop that developers work with within React is the children
prop. In the majority of cases, there is no need to understand how the children
prop looks like. But in some cases, we want to inspect the children
prop to maybe wrap each child in another element/component or to reorder or slice them. In those cases inspecting how the children
prop looks like becomes essential.
10 |
11 | You can use props.children in React in order to access and utilize what you put inside the open and closing tags when you are creating an instance of a component.
12 |
13 | For example, if I have a Button component, I can create an instance of it like this: ```