3.1 Responding to Events in React
Basic Example of Event Handling in React
function App() {
const handleClick = (e) => {
// Log the event object when the button is clicked
console.log(e)
// Alert showing the message
alert('I was clicked')
}
const handleMouseMove = (e) => {
// Log a message when the mouse moves over the button
console.log('Mouse is moving')
}
return (
<>
{/* Button that triggers both the click and mouse move events */}
<button onClick={handleClick} onMouseMove={handleMouseMove}>Click Me</button>
</>
)
}
export default AppForm Handling Example in React
import './App.css'
function App() {
// Function to handle form submission
const handleFormSubmit = (e) => {
// Prevent the default form submission behavior (page reload)
e.preventDefault()
// Log the event object to the console (which includes form data)
console.log(e)
// Log a message when the form is submitted
console.log("form was submitted")
}
// Function to handle username input change
const handleUsernameChange = (e) => {
// Capture the value of the input field as the username
const username = e.target.value;
// Log the username to the console
console.log(username)
}
return (
<>
{/* Form with a submit button */}
<form onSubmit={handleFormSubmit}>
{/* Label and text input for username */}
<label htmlFor="name">Name</label>
<input
id='name'
type="text"
name='username'
onChange={handleUsernameChange}
/>
{/* Label and password input */}
<label htmlFor="password">Password</label>
<input type="password" name="password" id="password" />
{/* Submit button */}
<button>Submit</button>
</form>
</>
)
}
export default AppForm Handling Example in React with onClick (Without Using it)
import './App.css'
function App() {
// Function to handle form submission
const handleFormSubmit = (e) => {
// Prevent the default form submission behavior (page reload)
e.preventDefault()
// Log the event object to the console (which includes form data)
console.log(e)
// Log a message when the form is submitted
console.log("form was submitted")
}
// Function to handle username input change
const handleUsernameChange = (e) => {
// Capture the value of the input field as the username
const username = e.target.value;
// Log the username to the console
console.log(username)
}
return (
<>
{/* Form with a submit button */}
<form onSubmit={handleFormSubmit}>
{/* Label and text input for username */}
<label htmlFor="name">Name</label>
<input
id='name'
type="text"
name='username'
onChange={handleUsernameChange}
/>
{/* Label and password input */}
<label htmlFor="password">Password</label>
<input type="password" name="password" id="password" />
{/* Submit button */}
{/* The form submission is handled by onSubmit, no need for onClick */}
<button>Submit</button>
</form>
</>
)
}
export default AppForm Handling Example in React with onClick
import './App.css'
function App() {
// Function to handle form submission
const handleFormSubmit = (e) => {
// Prevent the default form submission behavior (page reload)
e.preventDefault()
// Log a message when the form is submitted
console.log("form was submitted")
}
// Function to handle username input change
const handleUsernameChange = (e) => {
// Capture the value of the input field as the username
const username = e.target.value;
// Log the username to the console
console.log(username)
}
return (
<>
{/* Form with a submit button */}
<form>
{/* Label and text input for username */}
<label htmlFor="name">Name</label>
<input
id='name'
type="text"
name='username'
onChange={handleUsernameChange}
/>
{/* Label and password input */}
<label htmlFor="password">Password</label>
<input type="password" name="password" id="password" />
{/* Submit button with onClick handler */}
<button onClick={handleFormSubmit}>Submit</button>
</form>
</>
)
}
export default AppForm Handling Example in React with Both onSubmit and onClick
import './App.css'
function App() {
// Function to handle form submission
const handleFormSubmit = (e) => {
// Prevent the default form submission behavior (page reload)
e.preventDefault()
// Log a message when the form is submitted
console.log("form was submitted")
}
// Function to handle username input change
const handleUsernameChange = (e) => {
// Capture the value of the input field as the username
const username = e.target.value;
// Log the username to the console
console.log(username)
}
// Function to handle the submit button click
const handleButtonClick = (e) => {
// Log a message when the submit button is clicked
console.log('Submit button clicked')
}
return (
<>
{/* Form with both onSubmit and onClick handlers */}
<form onSubmit={handleFormSubmit}>
{/* Label and text input for username */}
<label htmlFor="name">Name</label>
<input
id='name'
type="text"
name='username'
onChange={handleUsernameChange}
/>
{/* Label and password input */}
<label htmlFor="password">Password</label>
<input type="password" name="password" id="password" />
{/* Submit button with onClick handler */}
<button onClick={handleButtonClick}>Submit</button>
</form>
</>
)
}
export default AppReact Event Handling with Child Components
import React from 'react'
const ChildA = (props) => {
const steps = 5
return (
<button onClick={() => props.handler(steps)}>Click Me Child A</button>
)
}
const ChildB = (props) => {
return (
<button onClick={() => props.handler()}>Click Me Child B</button>
)
}
const Event2 = () => {
const walk = (steps) => {
alert('I am walking ' + steps + " steps")
}
const eating = () => {
alert('I am eating')
}
return (
<div>
<ChildA handler={walk}/>
<ChildB handler={eating}/>
</div>
)
}
export default Event2React Event Handling with Child Components and Event Propagation
import React from 'react'
const ChildA = (props) => {
const steps = 5
return (
<button onClick={(e) => props.handler(steps, e)}>Click Me Child A</button>
)
}
const ChildB = (props) => {
return (
<button onClick={(e) => props.handler(e)}>Click Me Child B</button>
)
}
const Event2 = () => {
const walk = (steps, e) => {
alert('I am walking ' + steps + " steps")
e.stopPropagation()
}
const eating = (e) => {
alert('I am eating')
e.stopPropagation()
}
return (
<div onClick={() => alert('I am parent')}>
<ChildA handler={walk}/>
<ChildB handler={eating}/>
</div>
)
}
export default Event23.2 Introduction to State in React
Counter Component
import React from 'react';
// This is the Counter component
const Counter = () => {
// Initialize the counter variable
let counter = 10;
// Function to increment the counter value
const incrementCounter = () => {
counter++; // Increment counter by 1
console.log(counter); // Log the current value of the counter to the console
};
console.log("Rendered"); // Log that the component has rendered
return (
<div>
{/* Display the current value of the counter */}
<p>{counter}</p>
{/* Button to trigger the incrementCounter function when clicked */}
<button onClick={incrementCounter}>Increase Counter</button>
</div>
);
};
// Export the Counter component for use in other files
export default Counter;Counter Component with useState
import React, { useState } from 'react';
// This is the Counter component
const Counter = () => {
// Declare state variable 'counter' and the function to update it: 'setCounter'
const [counter, setCounter] = useState(0); // Initial counter value is 0
// Function to increment the counter value by 1
const incrementCounter = () => {
setCounter(counter + 1); // Update the state with the new counter value
// console.log(counter); // Uncomment to log the current counter value
};
console.log("Rendered"); // Log whenever the component renders (useful for debugging)
return (
<div>
{/* Display the current value of the counter */}
<p>{counter}</p>
{/* Button that triggers the incrementCounter function when clicked */}
<button onClick={incrementCounter}>Increase Counter</button>
</div>
);
};
// Export the Counter component for use in other files
export default Counter;
import React from 'react'
import Counter from './Counter'
const StateIntro = () => {
return (
<div>
<Counter />
<Counter />
</div>
)
}
export default StateIntroCounter Component with Conditional Rendering
import React, { useState } from 'react';
// This is the Counter component
const Counter = () => {
// Declare state variable 'counter' and the function to update it: 'setCounter'
const [counter, setCounter] = useState(0); // Initial counter value is 0
// Function to increment the counter value by 1
const incrementCounter = () => {
setCounter(counter + 1); // Update the state with the new counter value
// console.log(counter); // Uncomment to log the current counter value
};
// Function to decrement the counter value by 1
const decrementCounter = () => {
setCounter(counter - 1); // Update the state with the new counter value
// console.log(counter); // Uncomment to log the current counter value
};
console.log("Rendered"); // Log whenever the component renders (useful for debugging)
return (
<div>
{/* Display the current value of the counter */}
<p>{counter}</p>
{/* Conditionally render the decrement button if the counter is greater than 0 */}
{counter > 0 && <button onClick={decrementCounter}>Decrement Counter</button>}
{/* Conditionally render the increment button if the counter is less than 5 */}
{counter < 5 && <button onClick={incrementCounter}>Increase Counter</button>}
</div>
);
};
// Export the Counter component for use in other files
export default Counter;import React from 'react';
import Counter from './Counter'; // Import the Counter component
import { useState } from 'react';
// This is the StateIntro component
const StateIntro = () => {
// Declare a state variable to toggle visibility of the Counter component
const [showCounter, setShowCounter] = useState(true);
return (
<div>
{/* Conditionally render the Counter component based on 'showCounter' */}
{showCounter && <Counter />}
{/* Button to toggle the 'showCounter' state between true and false */}
<button onClick={() => setShowCounter(!showCounter)}>
Toggle Counter
</button>
</div>
);
};
// Export the StateIntro component
export default StateIntro;React’s Rendering Process
When the Counter component is added to the screen (by toggling showCounter to true), React will mount the component. This means React creates an instance of the component, attaches it to the DOM, and ensures it’s displayed on the screen.
When the Counter component is hidden (by toggling showCounter to false), React will unmount the component. Unmounting means React removes the component from the DOM, freeing up memory and resources until the component is rendered again.
This efficient system is part of React’s virtual DOM and reconciliation process. The virtual DOM is an in-memory representation of the actual DOM, and React uses it to minimize the number of updates to the real DOM, only applying necessary changes when the state or props change. This results in better performance because React avoids unnecessary re-renders or manipulations of the DOM, especially when working with large and complex UIs.
By efficiently managing which components need to be mounted, updated, or unmounted, React ensures smoother user experiences, even in complex applications.
3.3 How does React State work Internally?
React State Update Behavior
import React, { useState } from 'react';
// This is the Counter component
const Counter = () => {
// Declare a state variable 'counter' with initial value 0
const [counter, setCounter] = useState(0);
// Function to increment the counter multiple times
const incrementCounter = () => {
// The setCounter method updates the state, but React batches these updates
// It does not immediately reflect changes in the `counter` state until after all updates are processed.
// Increment counter by 1 multiple times
setCounter(counter + 1); // First increment (0 + 1 = 1)
setCounter(counter + 1); // Second increment (0 + 1 = 1)
setCounter(counter + 1); // Third increment (0 + 1 = 1)
setCounter(counter + 1); // Fourth increment (0 + 1 = 1)
// Since React batches updates, the final value of `counter` remains 1
// and does not immediately reflect the updated value of 4 increments.
console.log(counter); // Logs 0, because React batches the updates before reflecting them
};
return (
<div>
{/* Display the current value of the counter */}
<p>{counter}</p>
{/* Button that triggers the incrementCounter function when clicked */}
<button onClick={incrementCounter}>Increase Counter</button>
</div>
);
};
export default Counter;Counter Component with Local and State Variables
import React from 'react'
import { useState } from 'react';
const Counter = () => {
// Declare a state variable 'counter' with initial value 0
const [counter, setCounter] = useState(0);
// Local variable 'x' that is not tied to React's re-render cycle
let x = 0;
// Function to increment the counter multiple times
const incrementCounter = () => {
// Multiple calls to setCounter - React batches updates, so the state does not immediately reflect changes
setCounter(counter + 1); // First increment (0 + 1 = 1)
setCounter(counter + 1); // Second increment (0 + 1 = 1)
setCounter(counter + 1); // Third increment (0 + 1 = 1)
setCounter(counter + 1); // Fourth increment (0 + 1 = 1)
// Local variable 'x' is incremented immediately
x++;
// Logs the local variable 'x', which gets updated immediately within the function
console.log("x=", x); // Logs 'x= 1'
// Logs the state variable 'counter', which doesn't reflect the updated value immediately
console.log("counter=", counter); // Logs 'counter= 0' because React batches state updates
};
return (
<div>
<p>{counter}</p> {/* Displays the current counter value */}
<button onClick={incrementCounter}>Increase Counter</button> {/* Button to trigger increment */}
</div>
);
};
export default Counter;Counter Component with Local and State Variables
import React from 'react'
import { useState } from 'react';
const Counter = () => {
// State variable
const [counter, setCounter] = useState(0);
// Local variable
let x = 0;
// Increment counter function
const incrementCounter = () => {
// These two state updates will be batched by React
setCounter(counter + 1); // set counter to 1 (0 + 1)
setCounter(counter - 1); // set counter to -1 (0 - 1)
// Local variable 'x' is updated immediately
x++;
// Logging local variable and state variable
console.log("x=", x); // Logs '1'
console.log("counter=", counter); // Logs '0' due to batching
}
return (
<div>
{/* Display the current value of counter */}
<p>{counter}</p>
{/* Button that triggers incrementCounter on click */}
<button onClick={incrementCounter}>Increase Counter</button>
</div>
);
}
export default Counter;3.4 Sharing State Data Between Components
Parent to Child
import React from 'react'
import Child from './Child'
import { useState } from 'react'
const Parent = () => {
const [count, setCount] = useState(0)
const handleParentButton = () => {
setCount(prevCount => prevCount + 1)
}
return (
<div>
<p>Inside Parent: {count}</p>
<button onClick={handleParentButton}>Parent Button</button>
<Child count={count}/>
</div>
)
}
export default Parentimport React from 'react'
const Child = (props) => {
return (
<div>Child: {props.count}</div>
)
}
export default Child