React Scratch Book 2
React Scratch Book 2
Ajdin Imsirovic
This book is for sale at http://leanpub.com/react-from-scratch-book-2-hooks-and-forms
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
If you have complaints about the book, please write to me at [email protected] and I’ll do
my best to deal with the issue.
Also, any comments and kind words, as well as harsh criticisms, are all welcome.
Kind words from readers mean a lot.
Harsh criticisms, while I do find them usually not really neccessary, are a way to point me in the
right direction - and ultimately help me become a better technical writer and a better developer.
So I thank you either way.
1. I’ve shown to you how to install React Developer Tools in your browser.
2. I’ve introduced you to the create-react-app npm package, and I’ve shown to you how to use
this package to build a boilerplate React app.
3. I’ve explained all the files and folders in that boilerplate app, which goes a long way, because
now you’ll understand the basic structure of any React app built using this package
4. I’ve shown how you can update this starter app to change its output
0.2.10 Things covered in Chapter 10: The very basics of data and
events in React
In this chapter, I’ve covered the following:
1. Data
2. State data
3. Using events to update state data
Chapter 0: Before we start 5
1. if-else statements
2. classNames using ternary operators
3. a different value than the one in received in the props object
4. different components
5. components using the && operator
Essentially, what this boils down to is that we need to code our React apps to handle user events
which will in turn update a given component’s state.
That means that I need to:
In the first book of this book series, I’ve shown to you a basic example of how this is done.
As a starting point, here’s a quick reminder, A basic add-to-cart example, pt 3*.
The entire app was just a single component - the App component:
*https://codesandbox.io/s/a-basic-add-to-cart-example-pt-3-hqq0fr
Chapter 1: Understanding the useState hook 7
1. It will have the userName variable, which will be updated using the setUserName variable.
2. It will have the userAge variable, which will be updated using the setUserAge variable.
1. You can only update the user’s name and age once
2. You need to use the useState hook twice.
For now, let’s focus on updating the user’s name and age multiple times. In other words, making
sure that clicking the buttons will update the state forever.
A simple approach would be to check the previous state and act accordingly.
Here’s how.
17 <h1>User details:</h1>
18 <h2>{userName}</h2>
19 <h2>{userAge}</h2>
20 <button onClick={updateUsername}>Update username</button>
21 <button onClick={updateUserAge}>Update user age</button>
22 </>
23 );
24 }
The way that I’m making the buttons constantly “do something”, that is, constantly update the state,
is by using a simple ternary operator, which toggles back and forth between the two possible user
names, and the two possible user ages.
Of course, this is nothing special, but don’t worry, we’re building towards something more
impressive.
I’ve named this update to my app User name and age changer, pt 2*.
Now let me tackle the other issue, that is, the issue of having to use the useState hook twice.
15 <>
16 <h1>User details:</h1>
17 <h2>{user.name}</h2>
18 <h2>{user.age}</h2>
19 <button onClick={updateUsername}>Update username</button>
20 <button onClick={updateUserAge}>Update user age</button>
21 </>
22 );
23 }
I’ve named this update to my app User name and age changer, pt 3*.
However, this update is not really good.
While I did manage to have the useState hook use an object, I haven’t really succeeded in handling
button clicks properly.
There are two issues here:
1. First, I’m hard-coding the updates to state using setUser, which is not the React way of doing
it
2. Additionally, in my hard-coded updates, I’m updating the complete object, rather than the
specific property, that is, either the name, or the age
1. Returning a new object by cloning the previous value of the state object (using the spread
operator)
2. Updating a given specific property on the newly returned state object - based on which button
is pressed
*https://codesandbox.io/s/user-name-and-age-changer-pt-3-o3ekpf
Chapter 1: Understanding the useState hook 11
I’ve named this update to my app User name and age changer, pt 4*.
Again, similar to what we’ve had when the user data was saved as primitive values, again, I have
the issue of the buttons updating state only once.
So again, as an intermediate step in the development of this app, I’ll update it so that every button
click will update the state.
Here’s the newest update.
10 };
11
12 const updateUserAge = () => {
13 user.age === 21
14 ? setUser({ ...user, age: 25 })
15 : setUser({ ...user, age: 21 });
16 };
17
18 return (
19 <>
20 <h1>User details:</h1>
21 <h2>{user.name}</h2>
22 <h2>{user.age}</h2>
23 <button onClick={updateUsername}>Update username</button>
24 <button onClick={updateUserAge}>Update user age</button>
25 </>
26 );
27 }
I’ve named this update to my app User name and age changer, pt 5*.
This is the improved version of the app that showcases the useState hook in use.
Of course, this app can be improved even further, using forms. Specifically, this app would work
much better if instead of a button that a user can press, I had an input field where the user could
type a name in.
I’ll show you how to do exactly that in the next chapter.
*https://codesandbox.io/s/user-name-and-age-changer-pt-5-4kj5e6
Chapter 2: Forms in React
How do forms work in React? This is the chapter where I’ll introduce you to the topic.
1 function App() {
2 return (
3 <form>
4 <input type="text" placeholder="Enter User Name" />
5 </form>
6 );
7 }
8 export default App;
1 function App() {
2 return (
3 <form>
4 <input
5 type="text"
6 placeholder="Enter User Name"
7 onChange={changeHandler}
8 />
9 </form>
10 );
11 }
12 export default App;
1 function App() {
2 function changeHandler() {
3 alert('Change event fired!')
4 }
5
6 return (
7 <form>
8 <input
9 type="text"
10 placeholder="Enter User Name"
11 onChange={changeHandler}
12 />
13 </form>
14 );
15 }
16 export default App;
1 function App() {
2 function changeHandler(e) {
3 alert(e.target);
4 }
5
6 return (
7 <form>
8 <input
9 type="text"
10 placeholder="Enter User Name"
11 onChange={changeHandler}
12 />
13 </form>
14 );
15 }
16 export default App;
So, the e object instance of the built-in Event object is readily available. I then access the target
property of this object instance.
I’ve named this update to my app Input element in React, pt 3*.
This time, whenever a change is detected, I get the following output in the alert:
1 [object HTMLInputElement]
What this means is that my event’s target is an object of the HTMLInputElement type - in other words,
the input element itself - or, more specifically, the DOM object representing the input element.
The target property is also an object, which means that I can access properties that exist on it. One
of those properties is the value property, so let me update my app by alerting e.target.value.
This is the only update.
1 function App() {
2 function changeHandler(e) {
3 alert(e.target.value);
4 }
5
6 return (
7 <form>
8 <input
9 type="text"
*https://codesandbox.io/s/input-element-in-react-pt-3-lgc43i
Chapter 2: Forms in React 16
19 }
20 export default App;
Now that I have state at my disposal, I can update the code in the body of the changeHandler function
declaration to the following:
1 function changeHandler(e) {
2 setUser({...user, name: e.target.value})
3 }
Notice that I’ve added a wrapping div to the return, as well as an h1 that evaluates the value of the
user.name and the user.age variables as their text nodes.
This looks like a good opportunity to show you an example of a potential issue that you might be
facing as you work with objects, state, and forms in React.
1 Error
2 Objects are not valid as a React child (found: object with keys {name, age}). If you\
3 meant to render a collection of children, use an array instead.
*https://codesandbox.io/s/input-element-in-react-pt-6-7u3f1i
Chapter 2: Forms in React 19
24 }
25 export default App;
1 function changeHandler(e) {
2 const newStateObject = {...user};
3 newStateObject.name = e.target.value;
4 setUser(newStateObject);
5 }
So, this function works with an instance e of the Event object triggered by the app’s user typing into
the input.
I declare a newStateObject variable, and assign to it the cloned user state variable’s object.
Then I update the name value on the cloned object so that it receives the e.target.value string.
Finally, I use the setUser function to update the state variable with the value of the newStateObject.
I’ve named this update to my app Input element in React, pt 7*.
While this code is working, and in addition I am updating the old object’s state with the new object
- which is a general rule of how to properly update state, there is still something missing here.
Specifically, the usual way of updating state involves using arrow functions.
So now I’ll update my app using arrow functions to update state, in addition to using an arrow
function to save my event-handling function as a function expression.
First, I’ll update the changeHandler function so that the setUser function call inside of it uses an
arrow function, as follows.
1 function changeHandler(e) {
2 setUser(oldState => {
3 return {...oldState, name: e.target.value}
4 });
5 }
Note the oldState parameter - which is the previous value of the user object. Notice how I can
name it anything I want. I’m not really introducing anything new in this code. It’s pretty much the
same as what I had in the previous example.
Let’s further improve the changeHandler function by refactoring it as a named function expression.
Here’s the update:
*https://codesandbox.io/s/input-element-in-react-pt-7-he5fyp
Chapter 2: Forms in React 21
Again, the way my code works hasn’t really changed in this latest update. The goal here was just to
show you a more common way of how code is written in React.
The completed app now has the following code:
39 }
40 export default App;
1 setUser((oldState) => {
2 return { ...oldState, age: e.target.value };
3 });
Essentially, this is the same function. The only change that it gets is in the key. In this example, the
key is age, and for the previous input field, it would be name.
Luckily, JavaScript comes to the rescue here, and allows me to use its dynamic nature to keep my
code from being repetitive.
This solution takes a bit of time to wrap your head around it if you haven’t come across it before.
Luckily, I’ve already covered it in detail in my other book.
The text that follows is an excerpt from my book titled: A Better Way to Learn JavaScript, Book 1:
The Basics†.
*https://codesandbox.io/s/building-a-form-react-pt-1-xoild4
†https://leanpub.com/a-better-way-to-learn-javascript/
Chapter 2: Forms in React 24
1 function getACar() {
2 return {
3 lights: "off",
4 lightsOn() {
5 this.lights = "on";
6 },
7 lightsOff() {
8 this.lights = "off";
9 },
10 lightsStatus() {
11 console.log(`The lights are ${this.lights}`);
12 }
13 }
14 }
So far so good, we’re just returning our car object, which is exactly the same object like we had
before. We can now call the getACar function, and it will return our car object.
1 getACar();
17 return this.carType
18 },
19 getColor() {
20 return this.color
21 },
22 getYear() {
23 return this.year
24 }
25 }
26 }
27 getACar("sports car", "red", "2020").getType(); // returns: "sports car"
Now comes the fun part: to access a property in an object, we can either use the dot notation, or the
brackets notation.
This means that the following syntax is completely legitimate:
1 let aCarObj = {
2 [year]: "2020",
3 [color]: "red",
4 [carType]: "sports car"
5 }
6 aCarObj.carType; // returns: Uncaught ReferenceError: year is not defined
The returned error is completely expected, since we haven’t declared the year variable anywhere.
Let’s fix the error, like this:
Now, trying to access the carType property returns undefined instead of "sports car". Just why
that is so, can be seen if we just inspect the entire object:
Chapter 2: Forms in React 26
1 aCarObj;
This brings us to an a-ha moment: the brackets notation makes it possible to run expressions
inside of them. Actually, this is the regular behavior of the brackets notation.
What that means is that the values of the computed properties are indeed computed, which means
that the values of the variables are evaluated inside brackets and used as object properties’ keys.
Let’s rewrite the aCarObj:
1 let a = "year";
2 let b = "color";
3 let c = "carType";
4
5 let aCarObj = {
6 [a]: "2020",
7 [b]: "red",
8 [c]: "sports car"
9 }
10 aCarObj.carType; // returns: "sports car"
In the above code, the value of [a] was evaluated to year; the value of [b] was evaluated to color,
and the value of [c] was evaluated to carType.
This brings us to the point of this section. Just like we can use computed properties in the above use
case, we can use them on shorthand object methods, like this:
14 [lightsOnMethod]() {
15 this.lights = "on";
16 },
17 [lightsOffMethod]() {
18 this.lights = "off";
19 },
20 [lightsStatusMethod]() {
21 console.log(`The lights are ${this.lights}`);
22 },
23 [getTypeMethod]() {
24 return this.carType
25 },
26 [getColorMethod]() {
27 return this.color
28 },
29 [getYearMethod]() {
30 return this.year
31 }
32 }
33 }
34 getACar("sports car", "red", "2020").getType(); // returns: "sports car"
This is the end of the excerpt from my book titled: A Better Way to Learn JavaScript, Book 1: The
Basics*.
*https://leanpub.com/a-better-way-to-learn-javascript/
Chapter 2: Forms in React 28
And the issue that I was having were the duplicate event-handling functions - specifically, one event-
handling function for each element in the form.
Chapter 2: Forms in React 29
Now, based on the possibilities of making dynamic keys in our objects, I’ll update my code to the
following:
Notice that I’ve used another little trick here, which is the use of the name attribute in my inputs.
I’ve named this update to my app Building a form React, pt 2*.
*https://codesandbox.io/s/building-a-form-react-pt-2-qhq4xd
Chapter 2: Forms in React 30
So, I’ve used computed properties to dynamically set the key based on the event instance object,
that is, based on e.target.name.
Forms are probably one of the more difficult beginner-level concepts, because in HTML, they keep
their own state. Next, I’ll discuss this topic and how it relates to something known as “controlled
components”.
22 />
23 <input
24 type="number"
25 min="18"
26 max="130"
27 placeholder="Enter User Age"
28 onChange={changeHandler}
29 name="age"
30 value={user.age}
31 />
32 </form>
33 </div>
34 );
35 }
36 export default App;
*https://codesandbox.io/s/building-a-form-react-pt-3-bg2p29
Chapter 2: Forms in React 32
So, a working radio button is actually two elements working as a single element.
The input element’s state is controlled using the name attribute, and the label has a React-specific
htmlFor attribute which conncets the input element’s id attribute with the label element’s htmlFor
attribute. In other words, the id of “fish” in the input matches the htmlFor of “fish” in the label
element.
Notice also that each of the radio buttons has the exact same name attribute. This is so that only one
is clickable - that is, a user can select a single radio button, which excludes all the others at any given
moment.
Now that I have the structure set up, I still need to update my local state, and add the value attribute
to make it trully controlled.
12 }
13
14 return (
15 <div>
16 <h1>
17 {user.name}, {user.age}, likes {user.preferences}
18 </h1>
19 <form>
20 <div style={{ marginBottom: "20px" }}>
21 <input
22 type="text"
23 placeholder="Enter User Name"
24 onChange={changeHandler}
25 name="name"
26 value={user.name}
27 />
28 </div>
29
30 <div style={{ marginBottom: "20px" }}>
31 <input
32 type="number"
33 min="18"
34 max="130"
35 placeholder="Enter User Age"
36 onChange={changeHandler}
37 name="age"
38 value={user.age}
39 />
40 </div>
41
42 <div style={{ marginBottom: "20px" }}>
43 <input
44 type="radio"
45 name="preferences"
46 id="cats"
47 value="cats"
48 onChange={changeHandler}
49 />
50 <label htmlFor="cats">I'm a cats person</label>
51
52 <input
53 type="radio"
54 name="preferences"
Chapter 2: Forms in React 34
55 id="dogs"
56 value="dogs"
57 onChange={changeHandler}
58 />
59 <label htmlFor="dogs">I'm a dogs person</label>
60
61 <input
62 type="radio"
63 name="preferences"
64 id="parrots"
65 value="parrots"
66 onChange={changeHandler}
67 />
68 <label htmlFor="parrots">I'm a parrots person</label>
69
70 <input
71 type="radio"
72 name="preferences"
73 id="fish"
74 value="fish"
75 onChange={changeHandler}
76 />
77 <label htmlFor="fish">I like fish</label>
78 </div>
79 </form>
80 </div>
81 );
82 }
83 export default App;
Notice that although I’ve added the preferences property on my state object, to make it work
properly and reflect the radio button clicks, I also needed to add the onChange={changeHandler}
to each of the radio button input elements.
I’ve named this update to my app Building a form React, pt 4*.
Next, let’s discuss checkboxes.
2.8.2 Checkboxes
The default HTML behavior of checkboxes, contrary to radio buttons, is that you can select multiple
checkboxes at the same time.
*https://codesandbox.io/s/building-a-form-react-pt-4-78vnds
Chapter 2: Forms in React 35
Checkboxes are essentially a true/false state, implemented as an input element. What do I mean by
that?
Here’s an example:
The type attribute on the input element makes this a checkbox. The checked attribute is the true/false
state.
Additionally, the id attributes ties in with a label element, similar to how it works in radio buttons.
As far as keeping state goes, this is where things diverge from what I’ve showed you for other input
elements.
Before, we were controlling state using the value attribute. For checkboxes, we’ll need to use the
checked property in the state object, and we’ll need to set this property to a value that evaluates
either to true or false.
Here’s my update to state:
1 <div>
2 <input type="checkbox" id="olives" onChange={changeHandler} checked />
3 <label htmlFor="olives">Olives side dish</label>
4 </div>
And now I need to update my changeHandler function so that it can work with the checked attribute
as well:
Chapter 2: Forms in React 36
1 function changeHandler(e) {
2 const name = e.target.name;
3 const value =
4 e.target.type === "checkbox" ? e.target.checked : e.target.value;
5
6 setUser({ ...user, [name]: value });
7 }
34 </div>
35
36 <div style={{ marginBottom: "20px" }}>
37 <input
38 type="number"
39 min="18"
40 max="130"
41 placeholder="Enter User Age"
42 onChange={changeHandler}
43 name="age"
44 value={user.age}
45 />
46 </div>
47
48 <div style={{ marginBottom: "20px" }}>
49 <input
50 type="radio"
51 name="preferences"
52 id="cats"
53 value="cats"
54 onChange={changeHandler}
55 />
56 <label htmlFor="cats">I'm a cats person</label>
57
58 <input
59 type="radio"
60 name="preferences"
61 id="dogs"
62 value="dogs"
63 onChange={changeHandler}
64 />
65 <label htmlFor="dogs">I'm a dogs person</label>
66
67 <input
68 type="radio"
69 name="preferences"
70 id="parrots"
71 value="parrots"
72 onChange={changeHandler}
73 />
74 <label htmlFor="parrots">I'm a parrots person</label>
75
76 <input
Chapter 2: Forms in React 38
77 type="radio"
78 name="preferences"
79 id="fish"
80 value="fish"
81 onChange={changeHandler}
82 />
83 <label htmlFor="fish">I like fish</label>
84 </div>
85
86 <div>
87 <input type="checkbox" id="olives" onChange={changeHandler} checked />
88 <label htmlFor="olives">Olives side dish</label>
89 </div>
90 </form>
91 </div>
92 );
93 }
94 export default App;
I’ve named this temporary update to my app Building a form React, pt 5*.
1. The label on the checkbox input does not work. When you click it, nothing happens.
2. The radio buttons work, but initially, none are selected
*https://codesandbox.io/s/building-a-form-react-pt-5-xprhh4
Chapter 2: Forms in React 39
1 <input
2 type="checkbox"
3 name="olives"
4 id="olives"
5 onChange={changeHandler}
6 checked={user.olives}
7 />
8 <label htmlFor="olives">Olives side dish</label>
I’ve done this on purpose, so that I can emphazize the importance of the id and name attributes.
The id attribute is there to connect the label element to the input element.
The name attribute is there to connect the input element to the state object.
The id attribute is not required for the input element to work, but it is required for the label element
to work.
Secondly, let’s fix the radio buttons.
I’ll fix them by adding the checked attribute to each of the radio buttons, and I’ll add some JSX
evaluation so that it properly returns either true or false:
2.8.3 Textareas
In plain HTML, the textarea form element has an opening and a closing tag, with the starting state
value in between these tags, as a text node.
In React, effort was made to make this element as close to others as possible:
Let’s now extend our previous app example’s form with a textarea.
2.8.4 Selects
asdf
2.8.5 ???
asdfa
2.10 ???
asdf
Chapter 3: Revising components and
JSX
3.1 asdf
asdf
Chapter 4: Build a todo app
4.1 asdf
asdf
Chapter 5: Popular form libraries
5.1 asdf
asdf
Chapter 6: Popular component
libraries
6.1 asdf
asdf
Chapter 7: Build a portfolio app
7.1 asdf
asdf
Chapter 8: Deploy a portfolio app to
Netlify
8.1 asdf
asdf