React States, Passing Data and Lists, Event Handling
React States
In React, state is a built-in object that allows components to create and manage their own data. State is used to keep track of information that can change over time and influence what is rendered on the screen.
Using State
The useState hook is used to manage state. The useState hook returns an array with two elements: the current state value and a function to update it.
import React, { useState } from 'react';
function App() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
State Characteristics
Initialization:
- State can be initialized with a default value as an argument to
useState.
- State can be initialized with a default value as an argument to
Updating State:
State updates are asynchronous, and React may batch multiple
setStatecalls for performance reasons.The state should not be directly mutated. Always use
setState(class components) or the state updater function (functional components) to update the state.
Conditional Rendering:
- The state can be used to conditionally render parts of the UI.
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const toggleLogin = () => {
setIsLoggedIn(!isLoggedIn);
}
return (
<div>
{isLoggedIn ? <p>Welcome back!</p> : <p>Please log in.</p>}
<button onClick={toggleLogin}>
{isLoggedIn ? 'Log out' : 'Log in'}
</button>
</div>
);
}
- By default the value is set to
false, hence it will display asPlease log in.and after clicking it, it will sayWelcome backon the page.
Handling Multiple State Variables
You can use multiple useState hooks to manage different state variables in a functional component.
function App() {
const [name, setName] = useState("");
const [age, setAge] = useState(0);
const handleNameChange = (event) => setName(event.target.value);
const handleAgeChange = (event) => setAge(Number(event.target.value));
return (
<div>
<input type="text" value={name} onChange={handleNameChange} placeholder="Name" />
<input type="number" value={age} onChange={handleAgeChange} placeholder="Age" />
<p>Name: {name}, Age: {age}</p>
</div>
);
}
Using State with Objects
If your state is an object, updating it requires spreading the previous state to ensure all properties are preserved.
function App() {
const [user, setUser] = useState({ name: "", age: 0 });
const handleNameChange = (event) => setUser({ ...user, name: event.target.value });
const handleAgeChange = (event) => setUser({ ...user, age: Number(event.target.value) });
return (
<div>
<input type="text" value={user.name} onChange={handleNameChange} placeholder="Name" />
<input type="number" value={user.age} onChange={handleAgeChange} placeholder="Age" />
<p>Name: {user.name}, Age: {user.age}</p>
</div>
);
}
State is a fundamental concept in React, enabling components to maintain dynamic and interactive UIs.
Passing Data
There are cases when you want to pass the data from parent to child. Let's understand this while creating a list app and how we can pass the data to child components and use it. Here's how we can do it:
Suppose we have a component calledNote.jswhich is connected to ourApp.js:
import React, { useState } from 'react';
// Child component
import SingleNote from './SingleNote';
function Note() {
const [notes, setNotes] = useState([]);
const [curNotes, setCurNotes] = useState("");
function updateCurNote(event) {
setCurNotes(event.target.value);
}
function addNotes() {
const newNote = [...notes, curNotes];
setNotes(newNote);
}
return (
<>
<input type="text" onChange={updateCurNote} />
<button onClick={addNotes}>Submit</button>
<ul>
{notes.map((note, i) => {
{/* Sending the data to child */}
return (<li key={i}><SingleNote note={note}/></li>)
})}
</ul>
</>
);
}
export default Note;
State Management:
notes: An array to store all the notes.curNotes: A string to store the current input note.
Handlers:
updateCurNote(event): Updates thecurNotesstate whenever the user types into the input field.addNotes(): Adds the current note (stored incurNotes) to thenotesarray and updates thenotesstate.
Rendering:
An input field to capture the user's note, with an
onChangeevent that triggersupdateCurNote.A submit button that, when clicked, calls
addNotesto add the current note to the list.A list (
ul) that displays all notes. Each note is rendered as a list item (li) and passed as a prop to theSingleNotechild component.
Child component:
import React from 'react';
// Destructuring to directly access notes.
function SingleNote({note}) {
return (
<>
{note}
</>
)
}
export default SingleNote;
Else we had to writepropsinside the parenthesis and inside returnprops.note, like this:
import React from 'react';
function SingleNote(props) {
return (
<>
{props.note}
</>
)
}
export default SingleNote;
Passing Data From Child To Parent
We understood how we can pass the data from parent to child, but what if we wanted to pass the child data to parent instead? There can be many use cases related to this.
Let's create a counting app again and understand how we can create such a flow:
// Parent.js
import React, { useState } from 'react'
import Child1 from './Child1';
import Child2 from './Child2';
function Parent() {
const [countInParent, setCountInParent] = useState(0);
function updateCountInParent(count) {
setCountInParent(count);
}
return (
<>
<p>Inside parent: {countInParent}</p>
{/* A callback function from where we will take and store our data */}
<Child1 onCountUpdate={updateCountInParent}/>
{/* Passing the current value to the sibling of child1 */}
<Child2 countFromParent={countInParent}/>
</>
);
}
export default Parent;
State Management:
countInParent: A state variable in theParentcomponent to store a count value, initialized to 0.
Handlers:
updateCountInParent(count): A function that updates thecountInParentstate with a new count value passed as an argument.
Rendering:
A paragraph (
p) that displays the current value ofcountInParent.The
Child1component, which is passed a proponCountUpdatethat references theupdateCountInParentfunction. This allowsChild1to update the count in the parent component.The
Child2component, which is passed a propcountFromParentthat holds the current value ofcountInParent. This allowsChild2to access and use the count value from the parent component.
// child1.js
import React, { useState } from 'react'
function Child1(props) {
const [countInChild1, setCountInChild1] = useState(0);
function updateCountInChild1() {
setCountInChild1(countInChild1 + 1);
// Sending back the data to parent in callback
props.onCountUpdate(countInChild1 + 1);
}
return (
<>
<p>Inside child 1: {countInChild1}</p>
<button onClick={updateCountInChild1}>increment</button>
</>
);
}
export default Child1;
State Management:
countInChild1: A state variable in theChild1component to store a count value, initialized to 0.
Handlers:
updateCountInChild1(): A function that increments thecountInChild1state by 1 and then calls theonCountUpdateprop function (passed from the parent) with the updated count value (countInChild1 + 1).
Rendering:
A paragraph (
p) that displays the current value ofcountInChild1.A button that, when clicked, calls
updateCountInChild1to increment the count and notify the parent component of the new count.
// child2.js
import React from 'react'
function Child2(props) {
return (
<>
<p>Inside child 2: {props.countFromParent}</p>
</>
)
}
export default Child2;
This setup allows Child1 to send a count update to the parent component, which then updates its state and passes the updated count to Child2, ensuring that both child components can interact with and reflect changes in the parent component's state.
Event Handling
So far we have already seen few Event Handling's, such as onclick: When a user clicks in that area a certain function will be called. Such as that React supports a wide range of event types:
Mouse Events:
onClick,onDoubleClick,onMouseEnter,onMouseLeaveKeyboard Events:
onKeyDown,onKeyPress,onKeyUpForm Events:
onChange,onSubmitFocus Events:
onFocus,onBlurClipboard Events:
onCopy,onCut,onPaste
Event handling in React allows you to create interactive UIs by responding to user actions and updating the state or performing other actions based on those events.