State and Events

βœ… Objectives

  • Add event handlers to elements in React
  • Use the useState hook to create state variables
  • Create event handler callbacks that manipulate state
  • Trigger re-renders by setting state
  • Distinguish between props and state

πŸ“… Agenda

  • Handle events and introduce state by creating a click counter
  • Show that setState is asynchronous
  • Using setState with value vs function

Deliverables

  • Toggle Dark Mode Button Text on click
  • Exercise Add a ’like’ button to each project card
  • Filter / search by project name

Handling events in vanilla JS

  • In vanilla JS, our steps for handling events looked like this:
// 1. find a piece of DOM:
const taco = document.getElementById("taco")
// 2. Add an event listener to that piece
// 3. Give type and callback to the event listener:
taco.addEventListener("click", () => {
  console.log("taco has been clicked")
})
  • In React, we can skip step 1 and directly go to step 2 by adding event handlers to JSX. We apply an event listener with a callback.

Handling events in React

  • To implement a click handler on a taco button,
  • pass a callback function to the onClick attribute of the element.
function taco(){
  return(
    <button onClick = { () => {
      console.log("taco btn got clicked")
    }}> TACO </button>
  )
}

Don’t choose a wrong tool!

<button onClick={() => {
  console.log("taco clicked")
}}> TACO </button>
  • Events being attached to DOM elements
<ButtonComponent onClick = { () => {
  console.log(" why is this not working? ")
}}> TACO </ButtonComponent>```
  • Events being attached to our components -> Not going to work -> because it’s being passed down as a prop

Better Practice

  • Create a helper function for the callback function.
function counter() {
  
  const handleClick = (event) => {
    console.log(event)
  }

  return (
    
      <button onClick = {handleClick}> counter + </button>
    
  )
}

  • Why?
  • JSX should not be cluttered with JS codes. JS logic should mostly happen in the body of the function.

Synthetic Event

In React, a synthetic event is an abstraction over native browser events. Instead of directly working with the native event object provided by the browser (e.g. click, submit), React creates its own “synthetic” event object.

In React, event handling attributes are named using the “on” keyword as a convention. This makes it easier to distinguish event handlers from other attributes and helps maintain a consistent naming pattern.

State

  • State is private data to the component where it’s defined.

  • We can use this state to make our component more dynamic, trigger re-renders, and perform DOM manipulation based on how our state is manipulated.

states and props

  • Props are passed down from parents to children and remain static.

  • Meanwhile, values stored in state are meant to change, especially as the user interacts with the DOM.

  • This is a key component of declarative programming in React: we tie our components to our state by integrating values in state into logic (e.g., conditional rendering). This way, changes in state eventually cause changes to the DOM.

useState Hook : import

import React, { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);

  return <button>Count: {count}</button>;
}
  • 1 Import useState hook from react.
  • 2 Call useState with an initial value; in this case, it is 0.
  • 3 Use array destructuring to set the variable and setter function.

useState Hook : Array Destructuring

const [count, setCount] = useState(0);
  • count: the current value for the state variable
  • setCount: a setter function to update the state variable
const countState = useState(0);
// => [initialVal, setterFunction]

const count = countState[0];
const setCount = countState[1];
// => [0, setCount]
const arr = useState(0);
// => [0, setStateFunction]
const count = arr[0];
const setCount = arr[1];

useState Hook : Setter Function

  • To update a state variable, we use its setter function:
import React, { useState } from "react";
function Counter() {
  const [count, setCount] = useState(0);
  function handleClick() {
    setCount(count + 1);
  }
  return <button onClick={handleClick}>Count: {count}</button>;
}
  • Calling the setter function does two things:
    • It updates the state variable to some new value.
    • It causes our component to re-render and update the DOM.

πŸ€” Decisions

Two important decisions we’ll need to start making when working in React are:

  • What should be state? (vs props)
  • Where should state be?

πŸ€” Decisions - Should it be state?

From Step 3 of Thinking in React: to decide what we need as state, ask three questions about each piece of data:

  • Is it passed in from a parent via props? If so, it probably isn’t state.
  • Does it remain unchanged over time? If so, it probably isn’t state.
  • Can you compute it based on any other state or props in your component? If so, it isn’t state.

πŸ€” Decisions - Where should state be?

From Step 4 of Thinking in React: To decide where state should live, for each piece of state in your application:

  • Identify every component that renders something based on that state.
  • Find a common owner component (a single component above all the components that need the state in the hierarchy).
  • Either the common owner or another component higher up in the hierarchy should own the state.
  • If you can’t find a component where it makes sense to own the state, create a new component solely for holding the state and add it somewhere in the hierarchy above the common owner component.

Todo List for Today

  • Toggle Dark Mode Button Text on click
  • Exercise Add a ’like’ button to each project card
  • Filter by project name
  • We’ll go through toggling the Dark Mode button text now and then we’ll take a break!

β˜•οΈβ˜•οΈβ˜•οΈβ˜•οΈβ˜•οΈβ˜•οΈβ˜•οΈβ˜•οΈ

Break!

πŸ™†β€β™‚οΈπŸ™†β€β™‚οΈπŸ™†β€β™‚οΈπŸ™†β€β™‚οΈπŸ™†β€β™‚οΈπŸ™†β€β™‚οΈπŸ™†β€β™‚οΈπŸ™†β€β™‚οΈ