In the early web, sites contained nothing like the client-side interactivity which has come to constitute a contemporary standard
for building performant, effective, usable sites. Since its introduction in 1995, using Javascript in practice has extended far beyond
its original specification in addition to developing common, ubiquitous patterns and practices.
React is a Javascript library developed by Facebook in 2013. The library bridged a gap between web developer
best practices for building modular, component-based sites, and ease-of-use for integrating interactivity at
a component-by-component level.
At the time, Javascript libraries (and even Javascript itself) affected the entire DOM; React introduced
the principles that underlie the “Islands” architecture, re-rendering or modifying a narrower context with
respect to content rather than needing to re-render an entire page. Since the introduction of React, Javascript
itself has migrated more toward implementing similar principles at a language level, but does not have the
same ability to “bundle” functionality and apparent aesthetics together as easily. Hence, in the “framework wars”
that characterized the early 2010s to now, React has emerged as the clear all-around winner.
React is a library that implements Javascript. In effect, this means that:
React helps achieve common UI tasks using traditional Javascript patterns
React focuses on managing the user interface using a set of well-defined “syntactic sugar”
Using React allows developers to access a rich ecosystem of other librarys that codify well-known Javascript design patterns
The key features of React include:
Component-based architecture
Use of JSX (Javascript XML)
Unidirectional data flow (parent to child)
Hooks (such as useState and useEffect)
Advanced server-side integrations that allow for complete web application development
Like all very powerful things, useEffect is a sometimes food. In essence, this hook allows
a developer to defined functionality that should happen after a given control renders with
the following assumptions:
each state change triggers a re-render (i.e. clicks, et al.)
we need to use useEffect to modify the DOM outside of a component
we need to synchronize in-site data with external sources
Our ToggleComponent needs to update the root element, so we can use this tool:
useEffect(()=> {
// Call the document's <html> element
const root = document.documentElement;
if(isDark) { // Use the const representing dark status
JSX (Javascript XML) allows us to encapsulate (that is, isolate) the structure of a given component.
Essentially this limits our work to the “island” that we create; in this case, just the ToggleComponent.
We:
return (
// Create a label with the class "mode-toggle"
<labelclassName="mode-toggle">
<input
type="checkbox"
id="dark-mode-toggle"
// Hook up our change event to the control itself
onChange={HandleToggleChange}
/>
<spanclassName="slider"></span>
</label>
)
On each render, this component sends the above quasi-HTML back to the DOM. The CSS we’ve written
behind it transforms our control.
Among the most common patterns in Javascript are map and filter. These are array methods, meaning
they operate on arrays. These functions exist in several languages, and form the basis for how we can
manipulate data in both interactive controls and in astro files.
map allows us to take an array and transform it into a new array. For example, we can take an array of
numbers and create a new array where each number is doubled:
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(num => num * 2);
console.log(doubled);
Here, we see that the array doubled constitutes another array which contains the product of the
calculation of the “anonymous” function in the map method’s argument(s).
filter allows us to take an array and create a new array that only contains elements that satisfy
a certain condition. For example, we can take an array of numbers and create a new array that only contains
the even numbers:
const numbers = [1, 2, 3, 4];
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers);
Here, evenNumbers is the array produced by the filter method, which contains only the elements of numbers that
satisfy the condition specified in the anonymous function (i.e., being even).
We have 3 images that are identical except for their src attributes.
This is a common pattern in web development, and we can use map to simplify our code:
---
const images = [
"/img/picture_placeholder.png",
"/img/picture_placeholder.png",
"/img/picture_placeholder.png"
];
---
...
<divclass="full__three_column gap__3_rem">
{images.map(src=> (
<imgsrc={src}alt="Image placeholder" />
))}
</div>
This makes it easier to switch in/out images, should we want to change one without changing the markup around it,
preserving the underlying structure of our site while allowing us to manipulate the content more easily.