Skip to main content

Command Palette

Search for a command to run...

Exploring React JS ( Part 2 )

Published
•9 min read•View as Markdown

In this article we will be covering the following concepts :

  • Event handlers

  • use State in React, call-back function in setter function

  • Arrays as state variables, Objects as state variables

  • Forms

✅ Event Handlers in React

In React, event handlers are functions you attach to JSX elements to handle user interactions like clicks, typing, form submissions, etc.

They're similar to plain JavaScript event handlers, but written using camelCase and passed as function names (not strings or function calls).

🔹 Common Event Handlers :

onClick, onChange, onSubmit, onMouseOver, onKeyUp, onKeyDown


🧠 Examples

🔸 1. Click Event

function handleClick() {
  alert("Button clicked!");
}

function App() {
  return <button onClick={handleClick}>Click Me</button>;
}

🔸 2. Form Submit

function handleSubmit(e) {
  e.preventDefault(); // Prevent page reload
  console.log("Form submitted!");
}

function Form() {
  return (
    <form onSubmit={handleSubmit}>
      <button type="submit">Submit</button>
    </form>
  );
}

🔸 3. Input Change

import { useState } from "react";

function InputBox() {
  const [value, setValue] = useState("");

  const handleChange = (e) => {
    setValue(e.target.value);
  };

  return (
    <input
      type="text"
      value={value}
      onChange={handleChange}
      placeholder="Type something"
    />
  );
}

🧠 Things to Remember

✅ Use camelCase for event names
✅ Pass a function reference, not the result
✅ Use e.preventDefault() to stop default browser behavior (like form reload)


✅ Use State in React

In React, use State is a Hook that lets you add state to functional components.

Syntax:

import React, { useState } from "react";

function Example() {
  const [state, setState] = useState(initialValue);

  return (
    <div>
      <p>{state}</p>
      <button onClick={() => setState("new value")}>Change</button>
    </div>
  );
}

Key Points:

  • useState returns an array with two values:

    1. The current state value.

    2. A function to update the state.

  • You pass the initial state value into useState().

  • Updating state with the setter function re-renders the component.

  • Also [] is called array de-referencing as useState passes an array of 2 elements.

A basic example

import { useState } from "react"


function App() {

let [count, setCount] = useState(0)

function increaser(){
  setCount(count+1)
}

function decreaser(){
  setCount(count-1)
}

return <div>
  <div>The count is {count}</div>
<button onClick={increaser}>Increase count</button>
<button onClick={decreaser}>Decrease count</button>
</div>
}

export default App

In React useState, you can pass a callback function to the setter function instead of a direct value.

This is useful when the new state depends on the previous state.


Passing call back function in setter function

Syntax:

setState(prevState => newState)
  • prevState → the most recent state value.

  • newState → what you return becomes the updated state.


Example : Counter with callback

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

  const increment = () => {
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
// Clicking this btn once increases count value by 2
  };

  const decrement = () => {
    setCount(count-1);
    setCount(count-1);
/* Clicking this btn once will once decrease by 1 
coz all setCount calls are batched into a single call */
  };

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increment}>+1</button>
      <button onClick={decrement}>+1</button>
    </div>
  );
}

export default Counter;

Let’s use ternary operators with state

Ternary operators in React helps us in conditional rendering etc..

Eg:

function App() {
const r = false;
return <p> The result is {r == true ? "yes" : "no"} </p>
}

Toggle button

function App() {
const [result, setResult] = useState(true)

function toggle(){
  setResult(prevResult => !prevResult)
}

return <button onClick={toggle}> {result == true ? "yes" : "no"} </button> 
}

Complex State : Arrays

  1. Adding a new element to state array :

To add a element to state element, u can do the following in setter function:

old_array => [ ...old_array, new_item]

A Complete Example :

function App() {

let [list, setList] = useState([])

function adder(){
  setList(prevList => [...prevList, "item"])
}

return <div>
  <button onClick={adder}>Add a Item</button>
  <div>{list.map(item => <p>{item}</p>)}</div>
</div>
}
  1. Remove an element :

Similarly to remove a element, we filter all elements except target element, and pass that array into setter function.

Index will be unique for every element, so it is used as parameter in filter()

function App() {
  const [list, setList] = useState([]);

  function removeByIndex(indexToRemove) {
    setList(prevList => prevList.filter((_, index) => index !== indexToRemove));
  }

  return (
      <div>
        {list.map((item, index) => (
          <p key={index}>
            {item} <button onClick={() => removeByIndex(index)}>Remove</button>
          </p>
        ))}
      </div>
  );
}

export default App;

Complex State : Objects

To update a object state, or simply to change the value of a key to a new value, u can do it in setter function by:

old_object => { return

{ …old_object, key : new_value }

}

This will override old value to new value.

A Complete Example :


function App() {

  let [obj, setObj] = useState({
    firstName : "John",
    lastName : "Doe",
    mobile : 7884719748,
    relation : "doctor",
    isfav : false
  })

  function toggle(){
    setObj( prevObj => { return {
      ...prevObj, 
      isfav : !prevObj.isfav
    }
  })
  }
// or we can write this way

  function toggle2(){
    setObj( prevObj => ({
      ...prevObj, 
      isfav : !prevObj.isfav
    }))
  }


  return <div>
    <h2>{obj.firstName} {obj.lastName}</h2>
    <h4>mobile : {obj.mobile}</h4>
    <h4>relation: {obj.relation}</h4>
    <button onClick={toggle}>{obj.isfav ? <IoIosStar/> : <IoIosStarOutline/>  }</button>
  </div>

}

Handling Forms in React JS

  1. A basic form structure
function App() {

function submitHandler(event){
event.preventDefault()   // To prevent by default page refresh after submitting
// Bcoz of this auto refresh, even console log will appear once and then disappears
// But we still need that data to do some maipulation before getting vanished.
console.log("Form submitted")
}

return <div>
  <form onSubmit={submitHandler}>
  <label htmlFor="email">Email: </label>
  <input type="email" id="email" name="email"></input>
  <label htmlFor="passwd">Password:</label>
  <input type="password" id="passwd" name="password"></input>
  <button type="submit">Submit form</button>
  </form>
</div>
}
  1. Way to manipulate input data after submitting the form
function App() {

function submitHandler(event){
event.preventDefault()   
const formElement = event.currentTarget
const formData = new FormData(formElement)
const email = formData.get("email")
const password = formData.get("password")
console.log("Hey ", email, " ur password is ", password)
// And some other things like send to backend etc...
formElement.reset()
}

return <div>
  <form onSubmit={submitHandler} method="post">
  <label htmlFor="email">Email: </label>
  <input type="email" id="email" name="email"></input>
  <label htmlFor="passwd">Password:</label>
  <input type="password" id="passwd" name="password"></input>
  <button type="submit">Submit form</button>
  </form>
</div>
}
  1. Simplified way of phase 2 after React 19

Here, instead of passing handling functions to event handlers, u can pass them to action attribute itself, so that it will do following things by default so u dont have to code them again

i. Prevent by default page refresh

ii. Gives u directly formData instead of collecting it from event object

iii. Does formElement reset for u

iv. U don’t have to worry about form’s method attribute

function App() {

function submitHandler(formData){
const email = formData.get("email")
const password = formData.get("password")
console.log("Hey ", email, " ur password is ", password)
}

return <div>
  <form action = {submitHandler}>
  <label htmlFor="email">Email: </label>
  <input type="email" id="email" name="email"></input>
  <label htmlFor="passwd">Password:</label>
  <input type="password" id="passwd" name="password"></input>
  <button type="submit">Submit form</button>
  </form>
</div>
}

Other Key points to note:

  1. label tag needs id of its respective html input tag for its htmlFor attribute.

  2. formData.get(“abcd”) needs name of a html tag to get it’s content.

  3. Also, u can use defaultValue attribute in input tag so that if loads the input box will be filled by the default value.

Exploring other input types in Forms

  1. Radio buttons

    Here value attribute to radio box tags are important as we cant get content of its label with name of a radio tag, so we need to have value attribute.

     function App() {
    
     function submitHandler(formData){
     const result = formData.get("options")
     console.log(result)
     }
    
     return <form action={submitHandler}>
       <input type="radio" id="a" name="options" value="a"></input>
       <label htmlFor="a">Option a</label>
       <input type="radio" id="b" name="options" value="b"></input>
       <label htmlFor="b">Option b</label>
       <input type="radio" id="c" name="options" value="c"></input>
       <label htmlFor="c">Option c</label>
       <button type="submit" className="p-4 border-2">Submit</button>
       </form>
     }
    
  2. Check boxes

    Same as radio buttons but use getAll() instead of get() so that u get all selected values of checkboxes instead of only one.

     function App() {
    
     function submitHandler(formData){
     const result = formData.getAll("options")
     console.log(result)
     }
    
     return <form action={submitHandler}>
       <input type="checkbox" id="a" name="options" value="a"></input>
       <label htmlFor="a">Option a</label>
       <input type="checkbox" id="b" name="options" value="b"></input>
       <label htmlFor="b">Option b</label>
       <input type="checkbox" id="c" name="options" value="c"></input>
       <label htmlFor="c">Option c</label>
       <button type="submit" className="p-4 border-2">Submit</button>
       </form>
     }
    
  3. Select options

Here u have id and name attributes for select tag and value attribute for each option tag.

function App() {

function submitHandler(formData){
const color = formData.get("colors")
console.log(color)
}

return <div>
  <form action={submitHandler}>
  <select id="colors" name="colors">
    <option value="red">Red</option>
    <option value="green">Green</option>
    <option value="brown">Brown</option>
  </select>
  <button type="submit">submit</button>
  </form>
</div>
}

And,

We are generally getting only single value for 1 time with formData.get(“abc”). Instead we can get all values submitted by Object.fromEntries( formData ) in a single object.

function submitHandler(formData){
const all_data = Object.fromEntries(formData)
console.log(all_data)
}

State as props

1) Passing state variable as a prop.

import { useState } from "react"

function Value(props){
  return <p>{props.c}</p>
}

function App() {
let [count, setCount] = useState(0)

function inc(){
  setCount(prevCount => prevCount+1)
}

function dec(){
  setCount(prevCount => prevCount-1)
}

return <div>
  <Value c={count} />
  <button onClick={inc}>increase value</button>
  <button onClick={dec}>decrease value</button>
</div>
}

export default App

2) Passing state variable and the setter function too to the component. Even though we write event handlers on components, they don’t work as expected. They work as a prop instead. So, we have to receive that prop in component and apply that event handler function to actual html elements in component function.

// Star.jsx
import { IoIosStarOutline } from "react-icons/io"; // false
import { IoIosStar } from "react-icons/io"; // true

export default function Star({fav, toggler}){
    return  <button onClick={toggler}>{fav ? <IoIosStar/> : <IoIosStarOutline/>}</button>
}

// App.jsx
import { useState } from "react"
import Star from "./Star"
function App() {

  let [obj, setObj] = useState({
    firstName : "John",
    lastName : "Doe",
    mobile : 7884719748,
    relation : "doctor",
    isfav : false
  })

  function toggle(){
    setObj( prevObj => { return {
      ...prevObj, 
      isfav : !prevObj.isfav
    }
  })
  }

  return <div className="flex flex-col border-2 m-10 p-4">
    <h2>{obj.firstName} {obj.lastName}</h2>
    <h4>mobile : {obj.mobile}</h4>
    <h4>relation: {obj.relation}</h4>
    <Star fav={obj.isfav} toggler={toggle} />
  </div>

}

export default App

More on State and props

✅ Why Exporting a State Variable from One Sibling to Another is Not Possible

In React, each component manages its own local state. If you try to "export" a state variable from one sibling to another (i.e., pass data directly between sibling components), it won't work because:

  • Sibling components don't share state directly.

  • One component cannot access or modify another component's state.

  • React's data flow is unidirectional (parent → child).


🧭 The Solution: Lift the State Up to the Parent

To share data between sibling components, you lift the state up to their common parent component. The parent holds the state, and it passes the state (and any state-updating functions) down to the siblings as props.

🧱 Example

File: ParentComponent.js

import React, { useState } from 'react';
import SiblingA from './SiblingA';
import SiblingB from './SiblingB';

const ParentComponent = () => {
  const [sharedData, setSharedData] = useState('');

  return (
    <div>
      <SiblingA sharedData={sharedData} setSharedData={setSharedData} />
      <SiblingB sharedData={sharedData} />
    </div>
  );
};

export default ParentComponent;

File: SiblingA.js

import React from 'react';

const SiblingA = ({ sharedData, setSharedData }) => {
  const handleChange = (e) => {
    setSharedData(e.target.value);
  };

  return (
    <div>
      <h3>Sibling A</h3>
      <input type="text" value={sharedData} onChange={handleChange} />
    </div>
  );
};

export default SiblingA;

File: SiblingB.js

import React from 'react';

const SiblingB = ({ sharedData }) => {
  return (
    <div>
      <h3>Sibling B</h3>
      <p>Received Data: {sharedData}</p>
    </div>
  );
};

export default SiblingB;

🔁 Summary :

  1. ParentComponent holds the state (sharedData).

  2. SiblingA can update the state using setSharedData.

  3. SiblingB reads the state and displays it.