main.append(addSubHeader("Creating a React Component"));
main.append(addParagraph("When we created elements with ReactDOM.render, these are quite simple. In fact, these are the most atomic units in a React element, just as a simple tag such as a <p> tag is the most atomic element in HTML."));
main.append(addParagraph("In order to put together a user interface with reusable pieces, we create collections of React elements called components. Essentially, a component is a function that returns some interface."));
main.append(addParagraph("To demonstrate this, we will add a function to index.js which will replace the object we created previously."));
main.append(addInsetCodeListing(["function Hello() {"," return <h1>Welcome to React!</h1>","}"]));
main.append(addParagraph("We call this by simply putting the function name in a tag like this"));
main.append(addParagraph("although it is possible, and probably more common, to express this as a self-closing tag so"));
main.append(addSyntax("[<Hello />,"));
main.append(addParagraph("This replaces our previous tag in the call to ReactDOM.render so the index.js file now looks like this (see figure 29)."));
main.append(addImageWithCaption("./images/figure29.png","Figure 29 - creating a component which returns a user interface"));
main.append(addParagraph("This isn't hugely different to what we saw previously, but we can expand the function to incorporate different elements like this."));
main.append(addImageWithCaption("./images/figure30.png","Figure 30 - the expanded Hello function which is returning a more complex UI"));
main.append(addParagraph("There are a couple of things that should be mentioned at this point. Firstly, you will note that the tags being returned are enclosed in parentheses. This is not a requirement, but it makes the code a bit more readable since it emphasises the fact that we are returning a collection of elements rather than a single element."));
main.append(addParagraph("Secondly, it is a requirement that the name of the function should begin with a capital letter. We can see this if we change the code so that the function is called hello rather than Hello. The result is that the elements are not rendered and in this case, we simply see a blank web page."));
main.append(addParagraph("However, if you look in the console (in the Developer Options), you will see this warning."));
main.append(addSyntax("Warning: The tag <hello> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter. hello"));
main.append(addParagraph("For reference, the index.js file now looks like this"));
main.append(addImageWithCaption("./images/figure31.png","Figure 31 - the index.js file with a complete component and a call to that component"));
main.append(addParagraph("The output we see when running this is shown in figure 32."));
main.append(addImageWithCaption("./images/figure32.png","Figure 32 - the output from running the code in figure 31"));
main.append(addParagraph("So, to summarise, React components are collections of React elements that we can use to build user interfaces."));
main.append(addParagraph("React has an object called props (properties) that holds information about a component. We can start by passing props to our function"));
main.append(addParagraph("In order to see what this is doing, we want to log it to the console, so we will add this line to our function."));
main.append(addSyntax("[console.log(props);"));
main.append(addParagraph("We can then (possibly after refreshing the page) see an object logged to the console and this is an empty object (see figure 33)."));
main.append(addImageWithCaption("./images/figure15.png","Figure 33 - the props object viewed in the console. Note that it is an empty object at this stage"));
main.append(addParagraph("Now, we will give our object a property called library like this."));
main.append(addParagraph("We can make use of this property within our function like this"));
main.append(addSyntax("[<h1>Welcome to {props.library}!</h1>"));
main.append(addParagraph("This gives us the same output as before, but this time we are using the library property to return React rather than a literal value. This is also a dynamic property so if we change the name of the library to something like"));
main.append(addParagraph("Now, if we go and refresh our page, we will see the same header but a different paragraph below it (since the message property has a different message, obviously!) and we can also see the additional property in the object displayed in the console."));
main.append(addParagraph("You might notice that we are passing just string literals as our property values. We can also pass over a number, but this is slightly more complex in JSX in that the value must be enclosed in curly braces so"));
main.append(addParagraph("We can use this in the same way that we used the other properties. In this case, we will add a new paragraph element as follows."));
main.append(addParagraph("So that is sort of giving away the fact that the number, in this case, is simply a count of the number of properties we have given to the object, including the new property, number."));
main.append(addParagraph("The obvious flaw in this approach is that the total number of props was obtained by the user (in this case, me) simply counting the number of properties and inserting the appropriate number. A more dynamic approach would be to use the object itself to obtain this value so our paragraph containing the count becomes"));
main.append(addParagraph("This is more dynamic so, for instance, let's say we remove the number property which we are no longer using and refresh the page. We see that the count has been updated as shown in figure 34."));
main.append(addImageWithCaption("./images/image16.png","Figure 34 - using the props object to determine the number of properties our object has"));
main.append(addParagraph("We could also change our console.log statement to"));
main.append(addParagraph("This isn't required to make the code work, but it may help to clarify what is going on here. The props object is basically a hash object so each individual property is defined by a key-value pair where the key is the name of the property."));
main.append(addParagraph("By inspecting the object in the properties windows, we can see that the three keys (I reinstated the number property) are stored in an array. So, the keys method is returning an array with the names of each key as a separate element. That is, we call the method on Object and the result is an array that looks like this"));
main.append(addParagraph("We then use the length method (which is an array method) to return the number of elements in this array and then simply display that value as the number of properties the object has."));
main.append(addParagraph("Side issue, on the course video, the array is shown in the console, but I seem to be having an issue with this (see figure 35)."));
main.append(addImageWithCaption("./images/image7.png","Figure 35 - the output in the console when we are logging with console.log(Object.keys(props).length);"));
main.append(addParagraph("This seems to be a known issue, but it doesn't prevent the app from working. More information can be found here (relating to the issue in Chrome although I also see the same issue in Firefox)."));
main.append(addParagraph("I don't have time to fully investigate this at the moment, but one thing of note that I discovered with a quick look. In the terminal, if you type"));
main.append(addSyntax("[node --inspect"));
main.append(addParagraph("This initiates the node inspector. You can then go to chrome://inspect (actually, you can load this page without starting the node inspector). A similar URL doesn't seem to work in Firefox. That is as far as I got with the investigation but another useful link to note is"));
main.append(addParagraph("which, as the link suggests, takes you to the debugging introduction in the online documentation for node. I might as well add in the link to the node documentation which is"));
main.append(addParagraph("Going back to out React code, something else you will commonly see as a technique for introducing some brevity and readability to the code is to pass the properties in rather than the entire object. So, instead of "));
main.append(addParagraph("Now, rather than reference these with the object, as in"));
main.append(addSyntax("[<h1>Welcome to {props.library}!</h1>"));
main.append(addParagraph("we can simply reference them by name as in"));
main.append(addSyntax("[<h1>Welcome to {library}!</h1>"));
main.append(addParagraph("This works in exactly the same way. Again, we have made a few changes to the code, so it may be worth looking at the whole file again and this is shown in figure 36."));
main.append(addImageWithCaption("./images/figure36.png","Figure 36 - the main.js file with all the changes made in demonstrating the use of props and also best practice with respect to the syntax used in this context"));
main.append(addParagraph("And the output from this is"));
main.append(addImageWithCaption("./images/image18.png","Figure 37 - the output we get with the code shown in figure 36"));
main.append(addParagraph("I usually crop the output window to make our output much clearer, but in this case, I have shown the whole browser output so that we also see the error in the console (at the bottom)."));
main.append(addParagraph("To summarise, the props object provides data to a component to be displayed and a React component can be thought of as a function that takes in data as an argument (from props) and returns the React elements that create our user interface."));
main.append(addParagraph(" and components are building blocks and we can use these to build large and complex user interfaces. For this exercise, I will start with the index.js file after all the relevant changes have been made."));
main.append(addImageWithCaption("./images/figure38.png","Figure 38 - the index.js file with two functions, App and Lake"));
main.append(addParagraph("Here, we have removed the Hello function and added two others in."));
main.append(addParagraph("The function, App, returns a <h1> element. When developing this, we might want to consider creating this function and just having it return a string such as \"App\" and we can add in more complexity when we have other functions to provide data. So App would actually look like this, initially at least."));
main.append(addParagraph("The Lakes function is receiving props as an argument and it returns an <h1> element containing the value of the names property. So at this point, we have a function called App that simply returns a <div> element with some text and a function called Lakes which is returning an <h1> element with some data that has yet to be provided."));
main.append(addParagraph("Back in the App function, we will add the name property for Lake and give it a value of \"Lake Tahoe\". Now, if we run the code, the browser will display our <h1> element with a value of \"Lake Tahoe\"."));
main.append(addParagraph("In the course video, it is mentioned that the App function is now responsible for rendering the Lake. To me, this doesn't seem to quite ring true. It seems that the App function is responsible for rendering the data (in other words, it is creating a name property for Lake and giving it a value). The Lake function then renders the <h1> element in the browser."));
main.append(addParagraph("In any case, the important point is that we now have a function that we can reuse. Rather than providing a single value, we can provide multiple values simply by adding these additional lines to the App function."));
main.append(addParagraph("When we run the code with these additions, we see three <h1> elements, each with the name of a lake."));
main.append(addParagraph("If we inspect one of these elements, we will see that there is our root <div> and this contains the App div with three <h1> elements, as seen in figure 39."));
main.append(addImageWithCaption("./images/image19.png","Figure 39 - the result of inspecting our <h1> elements"));
main.append(addParagraph("If we click on the Components tab, we will see that App is the parent component to three Lake components (see figure 40)."));
main.append(addImageWithCaption("./images/image20.png","Figure 40 - inspecting the components"));
main.append(addParagraph("Actually, this makes a little more sense in respect to the statement that the App function renders the Lake. So, the Lake function returns an <h1> element and the App function injects these into a <div> and renders them to the browser. Of course, it does that via the call to ReactDOM.render so this, in fact, makes it perfectly clear that the App function is rendering the Lake objects to the browser."));
main.append(addParagraph("One final point to make is that we can also use the cleaner syntax we used in the previous exercise which allowed us to get rid of props. This gives us a final version of the index.js file as shown in figure 41."));
main.append(addImageWithCaption("./images/figure41.png","Figure 41 - the final version (for this section) of the index.js file"));
main.append(addSubHeader("Rendering Lists"));
main.append(addParagraph("So, we displayed three lake names and we rendered these as individual <h1> elements and this is probably fine for such small amounts of data. What happens when we want to display a much longer list, this could very quickly become unwieldy and so we will look at a way of rendering a list."));
main.append(addParagraph("Firstly, we will change the App function so that it has a placeholder, something like Eventual Lakes so the body of this function becomes"));
main.append(addParagraph("We removed the Lakes function and we are going to create a variable holding the list of names like this"));
main.append(addImageWithCaption("./images/figure42.png","Figure 42 - our list of lakes"));
main.append(addParagraph("Obviously, the list of lakes is in the form of an array. We can then pass that list of lakes to our App function like this"));
main.append(addParagraph("In our App function, we want to replace our placeholder with an unordered list which will contain the individual items from the list as list items. We could hard-code each individual list item in a <ul> element, but instead, we will pass the list over via properties. This means passing props over as an argument to the App function."));
main.append(addParagraph("Insider the function, we are going to be doing something that is a little more complex than anything we have seen up to this point, so I will copy the App function with the modifications to figure 43 and then describe it further."));
main.append(addImageWithCaption("./images/figure43.png","Figure 43 - the App function configured to return an unordered list containing the names of the lakes"));
main.append(addParagraph("Note that the line numbers shown in figure 43 are the line numbers for the function, within the file, the function actually appears on lines 11 to 19 (inclusive)."));
main.append(addParagraph("The interesting points are that we are passing the props object to our App function. The function is returning (as I noted above) a <ul> element."));
main.append(addParagraph("Within that element, we have this line which looks a little strange, I assume because this is syntax that is peculiar to React (or rather, to JSX)."));
main.append(addParagraph("Here, we have the props object which has the property, lakes. We are using the map function on this property. Bearing in mind the fact that the property has been given a value of lakesList and this is an array of lake names, I guess this could be considered to be the React equivalent of a foreach loop in Perl and very similar to a for loop in Java or C. Essentially, each element of the array is being returned in turn and we are assigning the returned value to lake."));
main.append(addParagraph("We then use this value in an <li> element. The result being that we will eventually render a <ul> element in the web page and for each element of the array, we will render a <ul> element within that <li> element."));
main.append(addParagraph("In practical terms, this means that the list of lakes will be rendered in the web browser as shown in figure 44."));
main.append(addImageWithCaption("./images/image21.png","Figure 44 - the unordered list of lakes displayed in a browser"));
main.append(addParagraph("Again, I haven't cropped the image because I wanted to show that in the Developer Tools, Components is selected and we can see the props object with its list of lakes in the bottom right."));
main.append(addParagraph("I am actually seeing a warning about this in the console which doesn’t appear in the course video but I am a bit dubious about what is shown in the console given the earlier problem so I am happy to ignore it. However, I have taken the time to ensure that there are no errors in the code."));
main.append(addParagraph("Finally, for this section, we can once again, tidy up the code by removing props so rather than pass props to the App function, we can just pass the lakes property and we can out props from the body of the function."));
main.append(addParagraph("The final version of the index.js file is therefore"));
main.append(addImageWithCaption("./images/figure45.png","Figure 45 - the final version (for this section) of the index.js file"));
main.append(addSubHeader("Rendering Lists of Objects"));
main.append(addParagraph("In the previous exercise, we rendered a list which was populated by the elements of an array. This was relatively simple since the items were simple string literals. We want to now look at a list of more complex objects."));
main.append(addParagraph("To start with, we will replace our list, lakesList, with the following."));
main.append(addImageWithCaption("./images/figure46.png","Figure 46 - our list, lakeList, modified so that each element is an object rather than just a string"));
main.append(addParagraph("If we make this change and then refresh the browser, we will see a lot of errors popping up. This isn't because the list is correct, but rather because we need to change how this is being accessed from the App function. In the previous example, we used the map function to iterate over our list of lakes and then output each lake in our unordered list."));
main.append(addParagraph("In this example, we will do something similar but since each list item is more complex, we will need to do some more complex processing on it. This time, our App function will return a <div>. Within that <div>, it will iterate over the list and return some elements for each list item. These elements are as follows."));
main.append(addParagraph("It may be worth quickly glancing back to figure 46 to remind ourselves that each element in our list of objects has three properties, id, name and trailhead."));
main.append(addParagraph("Aside - a trailhead, as you may have guessed, is the point at which a trail begins so when we say that the trailhead for Lake Maud, for example, is Wrights, this means that there is a trail that leads from Wrights Lake either to or past (presumably allowing a pleasant visit to) Lake Maud. According to Google Maps, there is both a Wright Lake and a Lake Maud in Wisconsin and it would take 46 hours to walk between them (given the most direct route for walking rather than a specific trail) so this sounds at least plausible."));
main.append(addParagraph("From this, I would conclude that Eve is an avid hiker!"));
main.append(addParagraph("Going back to our App function, every time we iterate through our list of objects, each element from our array of objects is being exposed and we can access the data from it. We only want to make use of two data items for each object and that is the name, which we will render in an <h2> element and the trailhead, which we will render in a <p> element. Both these elements will be rendered inside a <div> element and the entire list will be rendered inside a <div> element."));
main.append(addParagraph("The result is an App function that looks like this"));
main.append(addImageWithCaption("./images/figure47.png","Figure 47 - the App function modified to render the appropriate elements for a list of objects"));
main.append(addParagraph("The output from this is shown in figure 48."));
main.append(addImageWithCaption("./images/figure48.png","Figure 48 - the output we get when we run the code with the App function modified as shown in figure 47"));
main.append(addParagraph("If we inspect the Components in Developer Options, we can see that we are creating <div> elements containing our <h2> elements. In the Console, we see a warning relating to the fact that 'each child in a list should have a unique \"key\" prop. This is the same warning I referred to in the previous section and we will look at how we can clear this in the next section."));
main.append(addSubHeader("Adding Keys"));
main.append(addParagraph("I mentioned a warning just after figure 44 that wasn't visible in the course video, but it turns out that this was being ignored and we will look at how to resolve that now."));
main.append(addParagraph("As a reminder, figure 49 shows a screen shot of the app with the warning visible in the web console in the lower half of the browser."));
main.append(addImageWithCaption("./images/figure49.png","Figure 49 - the web app being viewed in a browser with the warning in the lower half of the browser."));
main.append(addParagraph("I didn't notice previously, but the warning also includes a link to the appropriate page in the online React documentation for fixing this which is quite handy. For reference, that link is <a href=\"https://reactjs.org/docs/lists-and-keys.html#keys\">https://reactjs.org/docs/lists-and-keys.html#keys</a>."));
main.append(addParagraph("The warning notes that 'each child in a list should have a unique key property' and as this suggests, the way to fix this is to add a key."));
main.append(addParagraph("A key is an identifier for a dynamically created element, but it also helps to keep track of any changes. That is, elements that may have been modified but also any elements that have been added or removed."));
main.append(addParagraph("Adding a key is quite simple and we can add it to the <div> as a property like this."));
main.append(addParagraph("For context, this is the <div> tag that we can see on line 5 of figure 47. Note that since each element in our list already has a unique identifier tag, we can also use this as the key."));
main.append(addParagraph("Now, if we save the change and refresh the browser, the page itself doesn't look any different, just as you would expect. However, the warning has disappeared."));
main.append(addParagraph("Before I go on to the next thing we want to look at, I will copy index.js below for reference."));
main.append(addImageWithCaption("./images/figure50.png","Figure 50 - index.js with our list of lake objects and a property added to the <div> to give each element of the list a unique key."));
main.append(addParagraph("Let's imagine that instead of out list of lake objects, we have a simpler list such as an array of integers."));
main.append(addSyntax("[const list = [1, 2, 3, 4, 5];"));
main.append(addParagraph("In this case, we don't have a unique identifier as we did with our lake objects, but we can use the value itself as a key. In our App function, we may want to display these numbers as an unordered list so the function would look like this"));
main.append(addImageWithCaption("./images/figure51.png","Figure 51 - the App function which is rendering an unordered list based on our array of integers and adding a key to each list item"));
main.append(addParagraph("Since the values are numerical and the key is a string value, we are using the toString function to convert them."));
main.append(addParagraph("If we are mapping over the list of values, we could also add some sort of iterator which can be used to create a value for the key."));
main.append(addImageWithCaption("./images/figure52.png","Figure 52 - similar to the code in figure 51, this time using an iterator to assign a key value which should avoid duplicate keys."));
main.append(addParagraph("The course video implies that the keys don't have to be unique, but you would normally want them to be since this would make it easier for React to keep track of the elements."));
main.append(addParagraph("You can use various conditions to determine whether a component should be rendered such as whether a user is logged in."));
main.append(addParagraph("As another example, suppose you have a website that recommends activities in a local area based on the season. For instance, you might want to visit a lake during the summer or a mountain during the winter. To start with, we will create a couple of functions, one for each of these."));
main.append(addImageWithCaption("./images/figure53.png","Figure 53 - the Lake() function"));
main.append(addImageWithCaption("./images/figure54.png","Figure 54 - the SkiResort() function"));
main.append(addParagraph("Either function returns a <div> containing an <h1> element. Inside the App function, we want to call one or the other of these functions and this will depend on the value of some variable."));
main.append(addParagraph("To do this, we will create a property in the ReactDOM.render function which we will call season and we will give it a value of \"\"summer\". We will pass props to the App function and this will use that the season property to return the appropriate element."));
main.append(addParagraph("The condition for this is"));
main.append(addParagraph("The App function in full, then, is"));
main.append(addImageWithCaption("./images/figure55 .png","Figure 55 - the App() function"));
main.append(addParagraph("The condition looks fairly similar to those you would see in most programming languages although do take note of the fact that the comparison operator in this case is ===."));
main.append(addParagraph("Note as well that there is only one condition tested. If it evaluates to true, in other words, if the season property has a value of \"summer\", the return statement below it (line 3 in figure 55) is executed and the function ends."));
main.append(addParagraph("If the condition doesn't return a true value (and, of course, this doesn't mean if the season property has a value of \"winter\", it just means that the value is not \"summer\"), we go onto the next statement after the if code block which is"));
main.append(addParagraph("So, essentially, we return the <div> created by the Lake() function when season has a value of \"summer\". If it has any other value, we will return the <div> created by the SkiResort() function."));
main.append(addParagraph("We can test this by running the code as is and seeing Visit Jenny Lake in the browser. We can then change the value to \"winter\" and refresh the browser to see Visit Jackson Hole Mountain and if we change it to anything else, let's say \"autumn\", we will still see Visit Jackson Hole Mountain in our browser."));
main.append(addParagraph("As with most other programming languages, we can make our conditions more complex, for instance by adding an else clause. It works in pretty much the way you might expect and so the App function becomes"));
main.append(addImageWithCaption("./images/figure56.png","Figure 56 - the App() function with two conditional statement"));
main.append(addParagraph("So here, we check whether (no pun intended) the season property is \"summer\" and display the appropriate element if it is."));
main.append(addParagraph("This time, if the season property doesn't have a value of \"summer\", the else clause checks it again and if it has a value of \"winter\", the appropriate element is displayed."));
main.append(addParagraph("In this case, however, there is nothing returned if the season property has a value of \"autumn\" (or anything other than the two values we are testing for). This means that we are handling both of the cases we created elements for, but for anything else, we are going to get an error such as"));
main.append(addSyntax("Error: App(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null."));
main.append(addParagraph("I won't fix that issue for the moment, but one possible solution would be to have another function, we might call that default, and have that display an appropriate message by returning it after all the conditions had been checked, much as we had returned the <div> from the SkiResort() function in our first version."));
main.append(addParagraph("For now, we want to tidy up our code a little by not having the names of the lake or ski resort hard coded into the Lake() and SkiResort() functions. Instead, when these are called form the App function, the name will be provided by the calling function. We do this by creating a property called name. This means changing the App() function as follows."));
main.append(addImageWithCaption("./images/figure57.png","Figure 57 - the App() function with the name property for Lake and SkiResort"));
main.append(addParagraph("Now, when we call the appropriate function, we can pass the name property over and use it in our message. For example, the Lake() function would now look like this."));
main.append(addImageWithCaption("./images/figure58.png","Figure 58 - the Lake({name}) function which makes use of the name property"));
main.append(addParagraph("We can make a similar change to the SkiResort() function and this works exactly as it did before."));
main.append(addParagraph("In React, as with other languages, when we want some code to execute when a condition is true and some other code to execute when it is false, we can wrap this up in a ternary if statement. This is quite common in React, but you can always achieve the same result with if statements, so you don't need to use this is you find it confusing."));
main.append(addParagraph("As with other languages, the general syntax is"));
main.append(addSyntax("[condition ? if true : if false;"));
main.append(addParagraph("In its simplest form, the ternary operator in this example would look like this"));
main.append(addParagraph("This is a little untidy, so we can insert some white space to tidy this up so the App() function is going to end up looking like this"));
main.append(addImageWithCaption("./images/figure59.png","Figure 59 - the App() function using a ternary conditional statement with some tidying up"));
main.append(addParagraph("Now, the ternary statement is going to return some value, in this case, either a Lake component or a SkiResort component but we still have the same problem that was mentioned earlier. Namely that our code treats any value that isn't \"summer\" as if it were \"winter\". We can fix this by changing our ternary operator so that, rather than return a SkiResort component if the initial condition is false, we can add a second ternary operator that checks whether the season has a value of \"winter\" and return a default component if this also returns false. So this would look something like this."));
main.append(addImageWithCaption("./images/figure60.png","Figure 60 - the App() function using a nested ternary conditional statement"));
main.append(addParagraph("Now, we are testing the season property to see if it has a value of \"summer\". If it does, we return a Lake component. If not, it will test the property again to see if it has a value of \"winter\" and will return a SkiResort component if it does. If the seconds test returns a false value, we will then return a generic <h1> element which covers all other options."));
main.append(addParagraph("I mentioned that it is possible to do the same thing with if statements, and that includes the default value. The code for that, would look like"));
main.append(addImageWithCaption("./images/figure61.png","Figure 61 - the App() function using an if..else structure rather than ternary operators"));
main.append(addParagraph("So, the code in figures 60 and 61 both do exactly the same thing in different ways. I guess which you would want to use depends on personal preference as much as anything else. I find that the syntax for the ternary operator adds some complexity and is less readable. I would be inclined to use the ternary operator in very simple cases, where a simple value is being returned but I think that nesting them is probably too messy so I would avoid doing that."));
main.append(addParagraph("That being said, it was also noted that the ternary operator is quite common in React so it is important to be able to recognise and understand it."));
main.append(addSubHeader("React Fragments"));
main.append(addParagraph("In the previous section, we used conditional statements to render one element or another. Now, let's assume we want to render both at the same time."));
main.append(addParagraph("To demonstrate how this works, we will remove all references to properties in our code and the Lake() and SkiResort() functions will return a simple <h1> element like this."));
main.append(addImageWithCaption("./images/figure62.png","Figure 62 - the index.js file with the changes so that we are trying to render two elements at the same time"));
main.append(addParagraph("When we try to run this, we get an error like this"));
main.append(addSyntax("./src/index.js SyntaxError: /home/philip/learning/react/exercise_files/Ch01/01_02/start/hello/src/index.js: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (20:2)"));
main.append(addParagraph("As noted in the error message, was can solve this problem by wrapping these two sibling elements in another element, let’s say a <div> so the App function becomes"));
main.append(addImageWithCaption("./images/figure63.png","Figure 63 - the App() function with our two sibling elements wrapped inside a <div> element"));
main.append(addParagraph("This works and both elements are rendered in the browser."));
main.append(addParagraph("Now, if I right-click on one of these elements in the browser, say \"Ski Resort!\" and select Inspect Element, I will see something like that shown in figure 64."));
main.append(addImageWithCaption("./images/image24.png","Figure 64 - the output in the browser with both elements rendered and inspecting one of the elements (see bottom left)."));
main.append(addParagraph("As we can see, our <h1> elements are inside a <div> which has been rendered by the App() function and this is inside the root <div>. Just as a reminder, the root <div> is not rendered by our React App, it has already been defined in the html file in our public folder and this is the file into which we are injecting our elements."));
main.append(addParagraph("You might consider this to be a little untidy and involving too many nested elements. However, React has a fairly new feature which is, perhaps, a little bit tidier and is designed to deal with sibling elements like this without the need to wrap those elements inside an additional tag. The syntax, however, can look as though we are doing that! The simplest way to do this is to replace the <div> tags in the code shown in figure 63 with what looks like a React.Fragment tag like this."));
main.append(addImageWithCaption("./images/figure65.png","Figure 65 - the App() function modified to wrap our two sibling elements in a React.Fragment"));
main.append(addParagraph("Superficially, the results will look exactly like those show in figure 64."));
main.append(addImageWithCaption("./images/image25.png","Figure 66 - the same output that we saw in figure 64 with our code modified as shown in figure 65."));
main.append(addParagraph("The difference is in the HTML tags. In the Inspector window, we can see the two sibling elements and these are inside the root <div>. So, on this occasion, the App() function has rendered our two sibling elements without wrapping then insider another tag. I guess you could think of React.Fragment as being a kind of pseudo-tag in that it allows us to meet the requirement of wrapping our adjacent JSX elements in an enclosing tag. This allows us to fix the error we saw when running the code shown in figure 62."));
main.append(addParagraph("However, it does that without injecting an enclosing tag into the root <div>, it only injects our sibling (or adjacent) elements."));
main.append(addParagraph("There is also a shorthand version of this where we can omit the words <React.Fragment> so we have what looks like empty tags."));
main.append(addImageWithCaption("./images/figure67.png","Figure 67 - the App() function using the shorthand version of a React fragment."));
main.append(addParagraph("We can also use a React fragment directly in the ReactDOM.render function. In this example, our App function isn’t doing anything except calling our two finctions, Lake() and SkiResort() to generate the two <h1> elements. Instead, we can get rid of the App() function and use a React fragment inside ReactDOM.render function in place of the call to the App() function."));
main.append(addImageWithCaption("./images/figure68.png","Figure 68 - generating a React fragment in the ReadDOM.render function"));