Client-side web pages / Single Page Apps (SPA)
- Consider Facebook: Notice that when you scroll down the page, you never get to the bottom. Instead, new posts get inserted and the list seems to go on “forever”
- This is an application of a technique called AJAX: Asynchronous Javascript and XML
- (Although, we tend to use JSON more than XML these days.)
- JavaScript running on the browser makes an HTTP request back to the server
- The server returns raw data (usually in XML or JSON form),
- The client-side JavaScript then inserts that data into the DOM (e.g., creates new posts and puts them at the end of the list.)
- This technique often involves creating new DOM elements on the fly (like we say last week).
- Client-side frameworks like React, Angular, and Vue take this to the extreme and construct the entire DOM on the client “on the fly”
- Such apps are called “single-page apps” because they are effectively just one page that is repeatedly updated.
- What are the advantages and disadvantages of such an approach?
- Advantages
- Faster
- Can feel more like a native app
- Can re-use the server for both web and mobile products
- Disadvantages
- “Deep linking” can be challenging.
- SEO can be challenging (but possible if you are careful)
- Code quality of SPAs may be lower (e.g., more redundancy)
- Cross-site scripting is a bigger issue.
- Advantages
Client-side “Quick Start”
- Every web page contains an object named
document
. This object describes the entire web page. - This object has several methods that allow us to grab specific elements
getElementById()
getElementsByClassName()
getElementsByTagName()
getElementsByName()
- Notice that all but the first one return a list of elements.
- Can run the above methods on other elements to search only part of the DOM.
- Once we have a “handle” on an element, we can manipulate it. We can
- Change the text
- Remove it from the DOM
- Add sub-elements to it.
- Change it’s style
- Load
basicDOMManipulation.html
. Open the console and rundocument.getElementById('favorite').innerHTML += " (My favorite")
document.getElementById('favorite').style.color = 'green'
document.getElementById('favorite').style.visibility='hidden'
document.getElementById('favorite').style.display='none'
document.getElementById('favorite').style.display='inline'
- Many fancy UI tricks are simply manipulating the DOM.
- First section: Callbacks
- Second section: Hiding elements
- Third section: Adding elements to the DOM
- Fourth section: Change listener / showing error message
- Note: Most of the
get
methods return a DOM list. This is not an array, so methods likeforEach
don’t work. - Look at
sortingStudents.js
- Look at
varVsLetSubtlty.js
(shows howlet
correctly sets up closure) - Look at
eventVsThis.html
(also shows how to clone nodes, when necessary) - Look at
placementOfScripts.html
(also shows how to clone nodes, when necessary)
React
- We can write JavaScript that will create an entire web page “on the fly”
- Look at
clientSideDomCreation.{html,js}
- Look at
- Using raw JavaScript would obviously be tedious, so React provides some helper methods
- Look at
reactDomCreation.{html,js}
- (You will need to launch a server – won’t run directly from a file)
- Look at
- Even this syntax would get tedious quickly, so React provides a more HTML-like syntax called JSX.
- Browsers can’t handle JSX directly. Code containing JSX needs to first be “transpiled” into straight JavaScript.
- Look at
jsx1.jsx
- To convert JSX to JavaScript “by hand”
- Install the Babel Command Line Interface:
npm install --save-dev @babel/core @babel/cli
- Install the React Preset for Babel:
npm install @babel/preset-react
- Run
npx babel --presets=@babel/preset-react jsx1.jsx
(npx babel
is a short-cut for./node_modules/.bin/babel
)
- Install the Babel Command Line Interface:
- Notice how the “html-like” syntax is converted into “regular” javaScript.
- (Note: The
jsx
extension is not necessary, I use it only because it makes VS Code happy.)
- (Note: The
- Like EJS and other templating languages, we can mix the JSX with “regular” javascript.
- Look at
jsx2.jsx
- How is this helpful? Imagine loading
states
from an API call.
- Look at
- With React/JSX we can define our own components. (It’s kind of like making up our own HTML tags on the fly.)
- A standard design approach is to break a page down into hierarchical (i.e., nested) components.
- Consider displaying recipes
- We can define components like this:
Recipe
,IngredientsList
,Instructions
,Ingredient
(not shown)
-
To create a new component, simply write a function that returns a React element:
function IngredientsList() { return React.createElement( "ul", {className: "ingredients"}, React.createElement("li", null, "1 cup unsalted butter"), ... React.createElement("li", null, "0.5 teaspoon salt"), ); }
-
Better yet, use JSX:
function IngredientsList() { return ( <ul className='ingredients'> <li>1 cup unsalted butter</li> ... <li>0.5 teaspoon salt</li> </ul> ); }
-
Even better: rather than hard-coding the ingredients, we can pass them as a parameter called
props
function IngredientsList(props) { return ( <ul className='ingredients"> {props.list.map((ingredient, i) => ( <Ingredient key={i} {...}> ))} ); }
- Look at
recipe1.jsx
in the sample code.
JSX Details
- JSX “in-depth” https://reactjs.org/docs/jsx-in-depth.html
- User-defined components must be capitalized.
- (Well, to be precise, the names those objects are assigned to must be capitalized.)
- built-in types like
<div>
and<span>
are lower-case
- The JSX element type can’t be a general expression.
- If the component you want to use is conditional, then use an
if
statement to assign the type to a variable.
- If the component you want to use is conditional, then use an
- Booleans, null, and undefined are ignored.
- However, 0 is not ignored (i.e., don’t assume all “falsy” values are ignored.)
- Shortcuts:
- You can set a prop to a string literal:
<MyComponent message="hello, world.">
- Props default to true
- Use the spread operator to pass an existing props object
- Long way:
<Greeting firstName='Ben' lastName='Hector" />
- Short way: `const props = {firstName: ‘Ben’, lastName: ‘Hector’}; <Greeting {…props}/>
- This is especially helpful when passing props down through a hierarchy.
- Long way:
- You can set a prop to a string literal:
Bootstrap and React
- To install Bootstrap in a React project:
- Add
npm
modulesbootstrap
andreact-bootstrap
- Add
import 'bootstrap/dist/css/bootstrap.css'
toindex.js
- Add
- Bootstrap in
AuthorsForm
:form-group
andform-control
classes (https://getbootstrap.com/docs/4.3/components/forms/)btn
andbtn-primary
- Bootstrap in
AuthorList
- The list is
container-fluid
- The table is set with
table
andtable-hover
(https://getbootstrap.com/docs/4.3/content/tables/) - Each table row is marked as a
row
withcol-md-3
so table stacks up at a medium size.
- The list is
Conventional React Deploy
- Including React from CDN is for development only.
- Conventional approach is to bundle all the code into a single .js file.
- Webpack (https://webpack.js.org): Tool used to bundle many JavaScript files into a single
.js
file - Babel: Converts code from one form to another. Used for two purposes:
- Convert JSX to JavaScript
- Convert imports into form that all browsers will understand.
- Webpack (https://webpack.js.org): Tool used to bundle many JavaScript files into a single
- If you used
create-react-app
you can just runnpm run build
- Look in
build
directory. You’ll see everything you need ready to go. - Launch a simple server (e.g., Python) and you are all set!
- Look in