Event handling in React
State is an internally managed configuration for any component. Let us take this example of creating a simple timer.
Example-State Management
Example-Event Handling
Inside a loop, it is common to want to pass an extra parameter to an event handler. For example, if id is the row ID, either of the following would work:
<button onClick={() => deleteRow(id)}>Delete Row</button>
// if you want the event also to be passed
<button onClick={(e) => deleteRow(id, e)}>Delete Row</button>
In both cases, the e argument representing the React event will be passed as a second argument after the ID. With an arrow function, we have to pass it explicitly, but with bind any further arguments are automatically forwarded.Handling Events
Handling multiple input tags with a single function
There are times that you have many input tags and you want to write a single function to handle it
const initState = {
name: "",
address: "",
email: "",
password: ""
}
function App(){
const [state, setState] = React.useState(initState)
const handleChange = e => {
const {name, value} = e.target
setState( { ...state, [name]: value} )
}
return (
<div>
<div>
<input type="text" name="name" placeholder="name" value={state.name} onChange={handleChange} />
</div>
<div>
<input type="text" name="address" placeholder="address" value={state.address} onChange={handleChange} />
</div>
<div>
<input type="text" name="email" placeholder="email" value={state.email} onChange={handleChange} />
</div>
<div>
<input type="password" name="password" placeholder="password" value={state.password} onChange={handleChange} />
</div>
</div>
)
}
Example: https://codepen.io/avinashvagh/pen/dymXxWd?editors=1010
Conditional Rendering:
Often you will want to render components based on a condition. This can easily be done in react by using a conditional if within the render function.
function App(){
if(condition){
return(
<Component if true />
)
}
else
return( <Component if false>)
}
Conditional rendering
//Simple button that changes from login to logout when it is clicked!
function App(){
const [isLoggedIn, setIsLoggedIn] = React.useState(false)
handleClick = () =>{
setIsLoggedIn(prev=>!prev);
// or
setIsLoggedin(!isLoggedIn)
}
if(isLoggedIn){
return <button onClick = {handleClick} >Logout</button>
}
else{
return <button onClick = {shandleClick}>Login</button>
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
https://codepen.io/avinashvagh/pen/eYMzqEz
You can also embed javascript expressions within JSX to perform conditional rendering.
Inline If-Else with Logical && Operator
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}
const messages = ['React', 'Re: React', 'Re:Re: React']; ReactDOM.render( , document.getElementById('root') );
Example: https://codepen.io/avinashvagh/pen/gOeMVxQ?editors=0010
Using the conditional(ternary) operator:
The conditional operator is often used as a shorthand for the if statement.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
This can be really useful in react for in-line conditional rendering. Here is the login button example with the conditional operator.
Conditional rendering with conditional operator
//Simple button that changes from login to logout when it is clicked!
function App (){
const [isLoggedIn, setIsLoggedIn] = React.useState(false)
const handleClick = () =>{
setIsLoggedIn( !isLoggedIn )
}
return isLoggedIn ? (
<button onClick = {handleClick} >Logout</button>
) : (
<button onClick = {handleClick}>Login</button>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
`
Example: https://codepen.io/albseb511/pen/PoGQLab
Preventing components from rendering:
Sometimes you may want to hide or delete components after rendering it.
To do this return null instead of any JSX in the render function.
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showWarning: true}
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(prevState => ({
showWarning: !prevState.showWarning
}));
}
render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
Example: https://codepen.io/avinashvagh/pen/qBoNePV?editors=0010
useRef hook
- There are times you want to maintain a state, and update it without the need to re render the component. Storybook
- if you want to persist the state between re-render of a component then we can use the useRef hook Refs provide a way to access DOM nodes or React elements created in the render method.
In the typical React dataflow, props are the only way that parent components interact with their children. To modify a child, you re-render it with new props. However, there are a few cases where you need to imperatively modify a child outside of the typical dataflow. The child to be modified could be an instance of a React component, or it could be a DOM element. For both of these cases, React provides an escape hatch.
const ref = React.useRef()
// ref = { current: null }
const elem = React.useRef()
const onNewMessage = () => {
elem.current.scrollTop = // value
}
return (
<>
<div ref={elem} >
// lets assume the container is a scrollable container
// and lets say if a user receives a new message, you want to push the scroll bar to the bottom part
// refs also can be assigned with a callback method like `ref = { n => elem = n }`
// useful if you have an array of refs elem[i] = n
</div>
</>
)
When to use Refs
When to Use Refs There are a few good use cases for refs:
- Managing focus, text selection, or media playback.
- Triggering imperative animations.
- Integrating with third-party DOM libraries.
- Avoid using refs for anything that can be done declaratively.
- make DOM manipulation like scroll behavior etc.
Example timer
const ref = React.useRef()
// ref = { current: null }
const startTimer = () => {
// if timer is not running then
const ref.current = setInterval(() =>{
setTimer(prev=>prev+1)
}, 1000 )
}
const stopTimer = () => {
clearInterval( ref.current )
}
React.useEffect(() =>{
startTimer()
return () => stopTimer()
// or
return stopTimer
}, [])
Example file handling
function Form(){
const file = React.useRef()
const handleSubmit = (e) => {
e.preventDefault();
console.log( `file is ${file.current.files[0]}` )
}
return (
<form onSubmit={handleSubmit}>
<input type="file" ref={file} />
<input type="submit" value="SUBMIT"/>
</form>
)
}
Forms
HTML form elements work a little bit differently from other DOM elements in React, because form elements naturally keep some internal state. For example, this form in plain HTML accepts a single name:
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
This form has the default HTML form behavior of browsing to a new page when the user submits the form. If you want this behavior in React, it just works. But in most cases, it’s convenient to have a JavaScript function that handles the submission of the form and has access to the data that the user entered into the form. The standard way to achieve this is with a technique called “controlled components”.
Controlled Components
In HTML, form elements such as input, textarea, and select typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with setState().
We can combine the two by making the React state be the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.
For example, if we want to make the previous example log the name when it is submitted, we can write the form as a controlled component:
function Form() {
const [value, setValue] = React.useState("");
const handleChange = (event) => {
setValue( event.target.value);
}
const handleSubmit = (event) => {
event.preventDefault();
alert('A name was submitted: ' + value);
}
render() {
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={value} onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Since the value attribute is set on our form element, the displayed value will always be this.state.value, making the React state the source of truth. Since handleChange runs on every keystroke to update the React state, the displayed value will update as the user types.
With a controlled component, every state mutation will have an associated handler function. This makes it straightforward to modify or validate user input. For example, if we wanted to enforce that names are written with all uppercase letters, we could write handleChange as:
handleChange(event) {
setState(event.target.value.toUpperCase());
}
Input Elements
When you are working with input elements like checkbox it uses the attribute checked to decide if the element is checked
const handleChange = e => {
setState( e.target.checked )
}
return (
<input type="checkbox" checked={checked} onChange={handleChange} name="checkbox" />
)
Uncontrolled Forms
In most cases, we recommend using controlled components to implement forms. In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself.
To write an uncontrolled component, instead of writing an event handler for every state update, you can use a ref to get form values from the DOM.
This is more common when you work with a third party UI library where form data is managed by the library.
For example, this code accepts a single name in an uncontrolled component:
function Form() {
const input = React.useRef();
const handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Subscribe to my YouTube channel, where I share remote job-hunting tips and opportunities → https://youtube.com/@AvinashVagh
Get Globally Full Remote Job Hiring Company’s details in your inbox | Remote Profile Newsletter → https://remoteprofile.beehiiv.com/subscribe
If you found this article useful, you can follow me for updates and you can follow me on Twitter and connect with me on LinkedIn & Meanwhile you can checkout my Hashnode Blog.
Stay fit untill next time, Keep coding, Keep going & speically Be happy with what you do.
Top comments (4)
Hello!
If you'd like, you can add syntax highlighting (colors that make code easier to read) to your code block like the following example.
This should make it a bit easier to understand your code. 😎
In order to use this in your code blocks, you must designate the coding language you are using directly after the first three back-ticks. So in the example above, you'd write three back-ticks js (no space between the two), put the code beneath (e.g.
console.log('Hello world!');
), then three back-ticks beneath that to close the code.Here's an image that shows how it's written!
Ooo Man, Thank yo so much for your Pro Tip, I just implemented it in my next article, You can check it out.
You dont need the input ref in the form example. If you give a name to the input, you can get the value of your input from the event when you submit the form:
Thank you so much Rense for sharing it, I appreciate it.