import { addBanner, addArticle, addTitle, addHeader, addParagraph, addClassParagraph, addSubHeader, addOrderedList, addUnorderedList, addBlockquote, addInset, addInsetList, addInsetCodeListing, addInsetBulletList, addImageWithCaption, addButtonGroup, addSidebar, addSyntax, menu, global_menu } from '/scripts/import.js'; import { local_menu } from '/scripts/webdev.js'; const heading = document.querySelector(".heading"); const global = document.querySelector(".global_menu"); const local = document.querySelector(".local_menu"); const sidebar = document.querySelector(".sidebar"); const main = document.querySelector(".main_content"); heading.append(addTitle("Learning ReactJS")); heading.append(addParagraph("Eve Porcello - LinkedIn Learning")); heading.append(addParagraph("Chapter 4 - React State with Hooks")); main.append(addSubHeader("Understanding Array Destructuring")); main.append(addParagraph("Let's say we have an array like this")); main.append(addImageWithCaption("./images/figure69.png", "Figure 69 - an array of snacks")); main.append(addParagraph("We can access individual elements of the array with conventional array syntax. For example, if we want to log the first snack to the console, we could do that with the command")); main.append(addSyntax("[console.log(snacks[0]);")); main.append(addParagraph("Similarly, we can change the index to obtain the second or third elements.")); main.append(addParagraph("We also have the option, in React of using a technique known as array destructuring in order to reference the arrays and this involves creating a reference to an individual element as follows.")); main.append(addSyntax("[const [first] = [")); main.append(addParagraph("Here, we have created a reference for the first element and we have just called it first. We can also create references for the other two elements and our array would then look like this.")); main.append(addImageWithCaption("./images/figure70.png", "Figure 70 - the same array of snacks as seen in figure 69 but with references to the individual elements")); main.append(addParagraph("Note that we don't have to create arrays for every element but they are in order. That is, the first reference is going to be applied to the first element and so on so if we wanted to, for example, create references for the first two elements, this is fairly straightforward.")); main.append(addSyntax("[const [first, second] = [")); main.append(addParagraph("However, if we want to create references for the first and third elements, we would do it like this.")); main.append(addSyntax("[const [first, , third] = [")); main.append(addParagraph("So, the second reference is empty and we are only creating two references.")); main.append(addParagraph("We can refer to the element in our code using the reference we created rather than the array name and index value which can make things easier, since we don't need to remember or know what that index value is.")); main.append(addParagraph("This is convenient, but the technique is also used when handling state in React applications, so it is important to be familiar with it.")); main.append(addParagraph("Just as a short aside before I move, primarily to act as a reminder for myself! To access a variable in React, you enclose it in curly braces. For example, let's say I want to display the first element of the snacks array in the <h1> element in the Lake component. I might want it to say something like")); main.append(addSyntax("[Lake! Bring your own popcorn!")); main.append(addParagraph("The existing component looks like this")); main.append(addInsetCodeListing(["function Lake() {", " return(", " <h1>Lake!</h1>", " )", "}"])); main.append(addParagraph("So we want to change line 3 to incorporate the variable name like so")); main.append(addSyntax("[<h1>Lake! Bring your own {snacks[0]}!</h1>")); main.append(addParagraph("Alternatively, if we are using a reference, the change might look like this.")); main.append(addSyntax("[<h1>Lake! Bring your own {first}!</h1>")); main.append(addParagraph("Another thing to point out here is that React can't use a variable until it has been declared and initialised. In these examples, we weren't too concerned about using the variable names in our React code, we were really just looking at the syntax. So, putting the array at the end of the code followed by the lines we used to log output to the console worked perfectly well.")); main.append(addParagraph("However, this wouldn’t work if we wanted to use the variable in the Lake() or SkiResort() functions so we would have to move the array declaration so that it comes before the function definitions.")); main.append(addSubHeader("Using useState")); main.append(addParagraph("We have already seen that whenever there is a change in the application, React will re-render. Previously, this has happened when there was a change in properties, but it will also happen if there is a change in state.")); main.append(addParagraph("We will start this section with a simple application with an App() function that renders a <h1> element displaying the word status. The code for this is shown in figure 71.")); main.append(addImageWithCaption("./images/figure71.png", "Figure 71 - a very basic app with an App() function that displays the word function.")); main.append(addParagraph("The intention is that this will also show a state value reflecting the current status of the application. In order to do this, we need to incorporate the useState hook from the React library. To do this, we will modify the import statement on line 1 in figure 71.")); main.append(addSyntax("[import React, { useState } from \"react\";")); main.append(addParagraph("It might be worth noting at this point that a hook is a function that allows you to add functionality to a component. A number of these are built into React.")); main.append(addParagraph("Next, we will create a constant inside the App() function and we will use array destructuring for the status value")); main.append(addSyntax("[const [status] = useState(\"Open\");")); main.append(addParagraph("Notice that we have passed the value, \"Open\", to the useState function so essentially we are stating that the status of the app is open.")); main.append(addParagraph("What we want to do is display the status (open) when the app starts so we are going to amend the <h1> element so that it also displays this information.")); main.append(addSyntax("[<h1>Status: {stauts}</h1>")); main.append(addParagraph("We can now refresh our app and we will see that it shows")); main.append(addImageWithCaption("./images/image26.png", "Figure 72 - our app showing the status")); main.append(addParagraph("The useState function returns a pair, the state value (which we have given a name of status using array destructuring) and the useState function which can be used to update the state. We can add this to our array destructuring and give it the name, setStatus.")); main.append(addSyntax("[const [status, setStatus] = useState(\"Open\");")); main.append(addParagraph("To really show this in action, we want to add a button with a caption of Closed. When clicked, the button will set the status to Closed. We will do this by using the button's onClick function to call setStatus with the appropriate value.")); main.append(addSyntax("<button onClick={() =>
setStatus(\"Closed\")}>Closed</button>")); main.append(addParagraph("We can also add a similar button which will allow us to set the status to Open if it is closed.")); main.append(addSyntax("[<button onClick={() =>
setStatus(\"Open\")}>Open</button>")); main.append(addParagraph("When we refresh the browser window, we can see that the buttons have been added and clicking on either one sets the status accordingly.")); main.append(addImageWithCaption("./images/image27.png", "Figure 73 - the app with our two buttons which change the app status added")); main.append(addParagraph("To summarise, a hook is a function that allows you to add some functionality to a component and useState is built-in hook designed to handle state changes in an application. It returns two things, the value of state and a function for changing the state.")); main.append(addSubHeader("Using Multiple State Variables")); main.append(addParagraph("Before I get on to the next section, I have switched the buttons round in the application to match the course video and added the additional break button which sets the status to 'Back in 5!'.")); main.append(addImageWithCaption("./images/image28.png", "Figure 74 - the app revised to match the course video")); main.append(addParagraph("So, the app us using useState to manipulate and display state. We can have multiple state values in the same component and we will demonstrate this by adding a constant called manager and a function called setManager to change its state (this is in the App function).")); main.append(addSyntax("[const [manager, setManager] = useState(\"Alex\");")); main.append(addParagraph("We will add another <h1> element in App() to display the name of the manager on duty and since this gives us adjacent elements, we will put both of them inside a fragment. This gives us an App() function as shown in figure 75.")); main.append(addImageWithCaption("./images/figure75.png", "Figure 75 - the App() function using multiple states")); main.append(addParagraph("We can add a similar button to the ones shown in figure 75 to update the state of manager.")); main.append(addInsetCodeListing(["<button onClick={() => setStatus(\"Rachel\")}>", " Break", "</button>"])); main.append(addParagraph("We will add another similar constant called with a setYear function which will initially have a value of 2050.")); main.append(addSyntax("[const [year, setYear] = useState(2050);")); main.append(addParagraph("We will also add a button to update this which will have a label of 'New Year!' and, when clicked, will increment the year.")); main.append(addSyntax("[<button onClick={() => setYear(year + 1)}>New Year!</button>")); main.append(addParagraph("So, there are different things we can do with state, we can overwrite it with a new value as we did with manager, perform some sort of calculation as we did with year and so on or we can implement multiple buttons, each setting state to a specific value (Open, Closed, Back in 5!).")); main.append(addSubHeader("Working with useEffect")); main.append(addParagraph("We are going to strip out most of the functions from our app now, including the App() function so we just have the import statements and the ReactDOM.render function. We will create a Checkbox() function and inside the ReactDOM.render() function we will render that check box. The code for this is as follows.")); main.append(addImageWithCaption("./images/figure76.png", "Figure 76 - code to render a check box element")); main.append(addParagraph("We can add a ternary operator to display the state of the check box like this.")); main.append(addSyntax("[{checked ? \"checked\" : \"not checked\"}")); main.append(addParagraph("This simply returns a string of text with the value \"checked\" if checked returns a true value and \"not checked\" if it returns a false value. This only works when the app is loaded, however, and it isn't updated if we change the state of the check box.")); main.append(addParagraph("To make sure that the displayed text does change when we change the state of the check box, we want to add an appropriate onChange method for the check box like this.")); main.append(addImageWithCaption("./images/figure77.png", "Figure 77 - the check box component with an added onChange function")); main.append(addParagraph("This is quite straightforward. The onChange function simply changes the state of the check box to the opposite value. Bear in mind the fact that a check box can only have one of two values, checked and not checked which is implemented as a Boolean variable (checked = true and not checked = false). So, if the state is checked (true) the onChange function, when invoked (that is when the check box is clicked) sets the value to not true (or false).")); main.append(addParagraph("Similarly, if the check box has a state of false and the onChange function is invoked, it will set the value to not false (or true) so it is, essentially a toggle switch.")); main.append(addParagraph("We can add an alert box our CheckBox() function like this.")); main.append(addSyntax("[alert(`checked: ${checked.toString()}`);")); main.append(addParagraph("This isn't part of the returned component. That is to say, the alert box is not part of the DOM and one of the consequences of this is that it is displayed before the element is rendered. It is, in fact, as side effect. For example, let's say the box is currently checked. If we uncheck, the sequence of events is as follows.")); main.append(addInsetBulletList(["the tick disappears from the box", "the alert box is displayed stating that checked = false", "we click ok on the alert and it disappears", "the text displayed changes from checked to not checked"])); main.append(addParagraph("So, we are displaying the state of the check box in the alert box before we have fully updated the component.")); main.append(addParagraph("To solve this problem, we can use another hook, this one called useEffect. It takes in a function and that function will return the alert.")); main.append(addParagraph("The alert then looks like this")); main.append(addInsetCodeListing(["useEffect(() => {", " alert(`checked: ${checked.toString()}`);", "});"])); main.append(addParagraph("As we saw with useState, we need to add this to the imports as well")); main.append(addSyntax("[import React, { useState, useEffect } from \"react\";")); main.append(addParagraph("If we refresh the app, we can see that now, when we click on the check box, the text displaying its state is updated immediately and the alert appears at the same time.")); main.append(addParagraph("I mentioned that the alert box is a side effect or an effect. Anything that a component does other than return UI elements is an effect, so this also applies to logging to the console or any interaction with the browser or a native API that is not part of the render. So it is something that is not part of the return. We can use an effect hook to handle these effects, in some cases. They can also allow us to do some other cool things in our applications to make them more interactive and to handle various types of functionality.")); addSidebar("webdev");