Basic Interactivity
"Basic Interactivity" introduces the core JavaScript and React elements that drive user interactions in web applications. We'll cover the essentials of Arrays, Arrow Functions, explore Anonymous and Higher Order Functions, and begin using the useState hook. This week is all about laying the groundwork for dynamic user interfaces, teaching you to transform static pages into responsive, interactive experiences.
JS Skills Needed
Mastering these JavaScript concepts will equip you with the essential tools to write clean, efficient, and more readable code in React. These skills will empower you to handle complex tasks such as managing user interactions and manipulating data effectively.
Arrays
In JavaScript, arrays are high-level, list-like objects that are incredibly versatile and serve as one of the basic data structures in the language. Understanding arrays and their common operations is crucial for any JavaScript developer.
Array Notation
Arrays in JavaScript are created and accessed using square bracket notation. Here is how you declare an array:
let myArray = ["apple", "banana", "cherry"];
In this example, myArray is an array containing three strings. The elements in the array are ordered and each one has an index, starting from 0. So, 'apple' is at index 0, 'banana' is at index 1, and 'cherry' is at index 2. You can access the elements of the array using their indexes like so:
console.log(myArray[0]); // Output: 'apple'
An empty array is an array that does not contain any elements. You can declare an empty array like this:
let emptyArray = [];
Even though the array is initially empty, you can still add elements to it later on which will increase by internally increasing the length of the array.
Destructuring Arrays
Destructuring is a JavaScript expression that makes it possible to unpack values from arrays or properties from objects into distinct variables. Here's an example of array destructuring:
let myArray = ["apple", "banana", "cherry"];
let [first, second, third] = myArray;
This example would be equivalent to:
let myArray = ["apple", "banana", "cherry"];
let first = myArray[0];
let second = myArray[1];
let third = myArray[2];
Destructuring can be a powerful tool for working with arrays and objects in JavaScript, making your code more concise and readable.
Arrow Functions
Arrow functions offer a more concise way to write functions in JavaScript. They are especially useful when defining short functions and can make your code more readable and maintainable.
Arrow functions have a syntax that's shorter than traditional function syntax. They also have some unique features, such as lexical this binding, but for now, we'll focus on their basic usage and syntax.
Basic syntax
Here's the basic syntax for an arrow function:
const myFunction = (parameters) => {
// function body
};
Example 1: A Simple Arrow Function
Let's start with a simple example. Here's a traditional function declaration:
function greet(name) {
console.log("Inside greet function");
return `Hello, ${name}!`;
}
console.log(greet("Daisy")); // Output: Inside greet function\nHello, Daisy!
And here's how you could write the same function as an arrow function:
const greet = (name) => {
console.log("Inside greet function");
return `Hello, ${name}!`;
};
console.log(greet("Daisy")); // Output: Inside greet function\nHello, Daisy!
Example 2: Arrow Function with Implicit Return
If your function body consists of just a single statement that returns a value, you can use the implicit return feature of arrow functions:
const greet = (name) => `Hello, ${name}!`;
console.log(greet("Bob")); // Output: Hello, Bob!
Notice that we've removed the curly braces and the return keyword. The value after the arrow (=>
) is implicitly returned.
Example 3: Arrow Function with Multiple Parameters
Arrow functions can of course take multiple parameters. Here's an example:
const add = (a, b) => a + b;
console.log(add(2, 3)); // Output: 5
In this example, the add function takes two parameters, a and b, and returns their sum.
Higher Order Functions
A higher order function in JavaScript is a function that either takes one or more functions as arguments, returns a function, or both. These types of functions are a key part of functional programming in JavaScript, and understanding them can lead to cleaner, more maintainable code.
Higher order functions allow us to abstract over actions, not just values. They can help reduce repetition in our code and make it more expressive and easier to read. They're a powerful tool in JavaScript, and they're used extensively in many popular libraries and frameworks, including React.
Example 1: Function as an Argument
One of the simplest examples of a higher order function is a function that takes another function as an argument. Here's an example:
const greet = () => {
return "Hello, world";
};
const shout = (func) => {
const greeting = func();
return `${greeting.toUpperCase()}!!!`;
};
const shh = (func) => {
const greeting = func();
return `${greeting.toLowerCase()}.`;
};
console.log(shout(greet)); // Output: HELLO, WORLD!!!
console.log(shh(greet)); // Output: hello, world.
In this example, shout
and shh
are a higher order functions because they take another function greet as its argument.
Example 2: Function as a Return Value
Higher order functions can also return other functions. Here's an example:
const multiplyBy = (num1) => {
// Return a new function that will multiply its given argument by num1
return (num2) => {
return num1 * num2;
};
};
const multiplyByTwo = multiplyBy(2);
console.log(multiplyByTwo(4)); // Output: 8
In this example, the multiplyBy
function returns a new function that multiplies its given argument by the value of num1
. We then assign the return value of multiplyBy(2)
to the variable multiplyByTwo
, which is a function that multiplies its given argument by 2. We can then call multiplyByTwo
with an argument of 4, which returns 8.
I know that concepts like arrow functions and higher order functions can seem complex initially, especially when you're starting your journey with JavaScript and React. However, these are fundamental constructs in modern JavaScript development, and mastering them will significantly improve your React programming skills. As you continue to practice and apply these concepts, they will become second nature. Remember, every experienced developer began where you are now, and through persistence and dedication, they've become proficient. So keep going, keep experimenting, and soon you will find yourself writing React code using these essential JavaScript features.
Tailwind CSS Skills Needed
Layouts
Display Classes
.block
: This class appliesdisplay: block;
to an element..inline-block
: Appliesdisplay: inline-block;
..flex
: Appliesdisplay: flex;
. This is the starting point for most flexbox layouts.
Flexbox Classes
.flex-row
: Setsflex-direction: row;
so that flex items line up horizontally..flex-col
: Setsflex-direction: column;
so flex items stack vertically..justify-start
,.justify-center
,.justify-end
,.justify-between
,.justify-around
,.justify-evenly
: These classes adjust the horizontal distribution of flex items (along the main axis)..items-start
,.items-center
,.items-end
,.items-baseline
,.items-stretch
: These classes adjust the vertical alignment of flex items (along the cross axis)..flex-grow
,.flex-shrink
,.flex-auto
,.flex-initial
,.flex-none
: These classes control how flex items grow and shrink to fill the available space.
Width and Height Classes
.w-
,.h-
: These classes set an element's width and height. You can specify a number from 0-100, a fraction (like 1/2), or a keyword like auto, full, screen.
Position Classes
.static
,.fixed
,.absolute
,.relative
,.sticky
: These classes set an element's position property..inset-
,.top-
,.right-
,.bottom-
,.left-
: These classes set the values of the top, right, bottom, and left properties.
Grid Classes
.grid
: Appliesdisplay: grid;
to an element..grid-cols-[number]
: Specifies the number of columns in a grid layout..gap-
: Specifies the size of the gap between grid items.
Layout Example
<div class="flex flex-row gap-4 m-4 w-full">
<div class="flex-1 bg-blue-100 p-6 rounded-lg">
<h2 class="mb-4 text-xl font-bold text-gray-900">Card 1</h2>
<p class="text-gray-700">
This is a simple card layout example using Tailwind CSS!
</p>
</div>
<div class="flex-1 bg-blue-200 p-6 rounded-lg">
<h2 class="mb-4 text-xl font-bold text-gray-900">Card 2</h2>
<p class="text-gray-700">This is the second card.</p>
</div>
<div class="flex-1 bg-blue-300 p-6 rounded-lg">
<h2 class="mb-4 text-xl font-bold text-gray-900">Card 3</h2>
<p class="text-gray-700">This is the third card.</p>
</div>
</div>
Card 1
This is a simple card layout example using Tailwind CSS!
Card 2
This is the second card.
Card 3
This is the third card.
Here we're using a flexbox layout to create a simple card layout with three cards. The flex
class sets the display property to flex, and the flex-row
class sets the flex-direction property to row, so the cards are laid out horizontally. The gap-4
class sets the gap between the cards to 1rem (16px). The m-4
class sets the margin to 1rem (16px) on all sides. The w-full
class sets the width to 100% of the parent element.
Tailwind States
In Tailwind CSS, "states" refer to the different states an HTML element can be in. For example, a button could be in a "hover" state (when the mouse is over it), a "focus" state (when it has keyboard focus), or a "disabled" state (when it is inactive and can't be clicked).
Tailwind provides utility classes to style these different states, which can be very helpful for providing visual feedback to users. For instance, you might want a button to change color when it's hovered over to indicate that it's clickable.
Here are some of the key states you can style in Tailwind:
hover
: Triggered when the mouse is over an element.focus
: Triggered when an element has keyboard focus.active
: Triggered when an element is being activated by the user (for example, a button being clicked).disabled
: Triggered when an element is disabled.visited:
Triggered when a link has been visited.
Hover Example
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Hover over me
</button>
In this example, the button's background color will change from blue-500 to blue-700 when you hover over it.
Focus Example
<input
class="focus:outline-none focus:ring-4 focus:ring-green-600"
type="text"
placeholder="Focus on me"
/>
Here, when the input field is focused, the outline is removed and a green ring appears around it instead.
Active Example
<button class="bg-blue-500 active:bg-yellow-700 text-white font-bold py-2 px-4 rounded">
Click me
</button>
In this case, the button's background color changes from blue-500 to yellow-700 when it's being clicked.
React Skills Needed
This week, we'll be focusing on four important aspects of React that are crucial for building interactive web applications. We'll learn about Event Handlers, which respond to user actions, and the useState Hook, a feature for managing state in your components.
Event Handlers
Event handlers in React are a core feature that enables interactivity in your web application. They are functions that get executed in response to specific events triggered by the user or the browser, such as clicks, mouse movements, key presses, form submissions, and more.
In React, event handlers are passed as props to components and are typically named with a "handle" prefix, such as handleClick
or handleInputChange
. Event handlers can perform a variety of tasks, from simple operations like updating the state of a component to more complex tasks like making API calls.
React events are named using camel case, rather than lowercase, and with JSX you pass a function as the event handler, rather than a string.
Example: Basic Click Event
In this example, when the button is clicked, an alert is shown:
export function ButtonExample() {
const handleClick = () => {
alert("Button clicked!");
};
return <button onClick={handleClick}>Click me</button>;
}
Detailed explanation:
- Component Definition: The component is defined as a function named ButtonExample. This is a functional component, which is the simplest type of component in React. Functional components are defined as functions that return JSX.
- Event Handler Definition: Inside the component, we define a function named handleClick. This function is an event handler β it's a function that will be called in response to a specific event. In this case, the event is a click event.
- The handleClick function uses JavaScript's arrow function syntax, and all it does is call the alert function with the message "Button clicked!". The alert function is a built-in browser function that shows a popup message to the user.
- JSX Return Statement: The component returns a JSX expression.
- The JSX expression in this component is a single button element. This button has a prop onClick set to the handleClick function we defined earlier.
- onClick Prop: The onClick prop is a special prop in React that allows you to specify a function to be called when the button is clicked. When you click the button in a web browser, React will call the handleClick function, causing the alert to be shown.
- Button Text: The text inside the button is "Click me". This is what will be displayed on the button in the browser.
So, all together, this ButtonExample component renders a button that, when clicked, shows an alert with the message "Button clicked!".
useState
Hook
What is State?
In the context of React (and many other programming paradigms), "state" refers to the data that a program or component needs to keep track of and possibly modify over time. This could be anything from the current value of a form input, to whether a dropdown menu is open or closed, to more complex data like the contents of a shopping cart on an e-commerce website.
Why is State Important?
State is a fundamental concept in React because it allows components to create and manage their own data. Without state, a component would render the same output every time it's called, making it essentially static. But with state, a component can render different output in response to different state, making it dynamic and interactive.
For example, a button that shows a count of how many times it's been clicked wouldn't be possible without state. The component needs some way to remember how many times the button has been clicked, and that's exactly what state provides.
State vs Variables
You might be wondering why we can't just use regular JavaScript variables instead of state. The answer is that state in React has a special property: when state changes, React automatically re-renders the component with the new state.
On the other hand, changes to regular variables don't cause a re-render. If you tried to use a regular variable instead of state for the click count in a button component, the count would increase when the button is clicked, but you wouldn't see the count update in the UI because the component wouldn't re-render. In addition, regular variables get recreated with every render, and their values get "reset" each time, which is why they cannot be used for values that need to persist across renders.
The useState
Hook
React's useState hook is a feature that allows you to add state to your function components. The useState hook is a function that accepts one argument: the initial state. It returns an array with two elements: the current state and a function to update the state.
The state updating function can be used to update the state with a new value. When the state is updated, the component re-renders with the new state.
Example 1: Basic State Usage
A simple counter that increments when a button is clicked:
import { useState } from "react";
export function CounterExample() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
Let's break this example down.
import { useState } from "react";
First, we're importing the useState hook from React. This is a built-in React hook that allows us to add state to our function components.
const [count, setCount] = useState(0);
Within our component, we're calling the useState function with an initial value of 0. useState returns an array with two elements: the current state value and a function to update that state value. Here, we're using destructuring assignment to assign these two elements to the count and setCount variables, respectively.
The count
variable holds the current state (the number of times the button has been clicked), and setCount
is the function we'll use to update this state.
const increment = () => {
setCount(count + 1);
};
increment
is a function that, when called, uses setCount
to update the count
state to be one higher than it currently is.
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
In the render return of our component, we're displaying the current count
inside a paragraph tag, and a button that, when clicked, calls the increment function, which increases the count by one. When the count is updated, the component re-renders with the new count value.
State is a fundamental concept in React, and it's important to understand how it works. If you're still confused about state, don't worry β we'll be revisiting this topic in more detail in a couple weeks.
Next.js Skills Needed
"use client"
Directive
By default, Next.js renders all pages on the server side. This means that when a user visits a page, the page is rendered on the server and the resulting HTML is sent to the browser. This is known as server-side rendering (SSR).
However, there are some cases where you might want to render a page or component on the client side (browser) instead. For example, if you want to use useState
to manage state, you must render it client side since useState
is a React hook that only works in the browser.
If you don't use "use client"
and try to use useState
in a component, you'll get an error like this:
You're importing a component that needs useState. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
Learn more: https://nextjs.org/docs/getting-started/react-essentials
.....
In this case, just put "use client"
at the top of the file to mark it as a client-side component:
"use client";
import { useState } from "react";
export default function .....
ποΈ Summary
- π― Focus: Interactivity is key in modern web applications and React provides a robust framework to create interactive user interfaces.
- πΉ JS Skills: Master JavaScript concepts like arrow functions that offer a concise way to write functions, and higher order functions that take one or more functions as arguments or return a function.
- π¨ Tailwind CSS: Learn about layouts, Tailwind states, and how to use utility classes to create custom designs.
- πReact Skills: Learn about Event Handlers, the useState Hook.
- π±οΈ Event Handlers: Functions executed in response to specific events triggered by the user or the browser.
- π useState Hook: Allows you to add state to your function components.
π Knowledge Check
const myFunction = (parameters) => { // function body };
const myFunction => (parameters) { // function body };
const myFunction = parameters => { // function body };
arrowFunction myFunction = (parameters) => { // function body };
The initial state value
An array with two elements: the current state and a function to update it
An object with two properties: state and setState
The updated state value
A function that is declared inside another function
A function that is exported for use in another module
A function that either takes one or more functions as arguments, returns a function, or both
A function that is declared using the 'function' keyword
Rendering components based on certain conditions
Rendering only the components that are visible on the screen
Rendering components in a specific order
Rendering components that are conditional on user interaction
State is a special property: when state changes, React automatically re-renders the component with the new state
State can be updated, but regular variables cannot
State can only hold strings, but regular variables can hold any data type
State is stored in the browser's local storage, but regular variables are not
Props that are passed to components
Functions that are executed in response to specific events triggered by the user or the browser
Functions that are called when a component is rendered
Components that handle events
Using JavaScript functions
Using CSS classes
Using special Tailwind components
Using HTML attributes
It allows us to abstract over actions, not just values
It allows us to create functions with a higher order of complexity
It allows us to declare functions inside other functions
It allows us to use functions as arguments to other functions
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
console.log(count);
};
It decreases the 'count' state by 1
It sets the 'count' state to 1
It increases the 'count' state by 1
It sets the 'count' state to 0
The updated value of 'count', incremented by 1
The initial value of 'count' before being incremented
The value of 'count' after two increments
The value of 'count' from the previous render
π Activity
In this hands-on activity, you will be enhancing a basic counter application by adding a new piece of state and a function to toggle this state. This will give you the opportunity to practice creating and updating state in a React component.
The provided code includes a counter with an increment button. Currently, the increment button is always disabled. Your task is to implement a feature that enables/disables the increment button when a checkbox is checked/unchecked and add a class to make the button appear interactive when hovered over.
π‘ Hints
Create a new piece of state
Locate the following comment in the code:
// TODO: Create a new state variable called `isEnabled` with an initial value of false.
// This variable will be used to control the enabled/disabled state of the increment button.
In this spot, create a new piece of state called isEnabled
with useState
. The initial value should be false
.
Implement a function to toggle the state
Next, find the toggleEnabled function:
const toggleEnabled = () => {
// TODO: Implement a function that toggles the value of 'isEnabled'.
// If `isEnabled` is currently true, it should be set to false, and vice versa.
};
Inside this function, implement logic to toggle the value of isEnabled
. If isEnabled
is currently true
, it should be set to false
, and vice versa.
Add a hover class to the button
Currently, the increment button has the following classes:
className = "bg-blue-400 disabled:bg-yellow-900 rounded m-4 p-4";
Your task is to add a Tailwind CSS class to the button to make the button turn a darker shade of blue when it is hovered over, providing a visual indication that it is interactive.
β Solution
π Community Events App
In order to create a new event, users need to fill out a form with details about the event. This form will be a modal (pop-up) that appears when the user clicks the add button. In the Community Events app for Week 4, let's implement the modal. Next week we will add the form fields.
π Further Reading
JavaScript:
- Arrays (opens in a new tab)
- Arrow function expressions - JavaScript | MDN (opens in a new tab)
- Higher-Order Functions :: Eloquent JavaScript (opens in a new tab)
Tailwind CSS:
React:
- Adding Interactivity - React (opens in a new tab)
- Responding to Events - React (opens in a new tab)
- State: A Component's Memory - React (opens in a new tab)
- Render and Commit - React (opens in a new tab)
- State as a Snapshot - React (opens in a new tab)
Next.js: