Welcome! Today's journey explores how React handles user input in functional components. We will cover Refs, a feature for managing certain functionalities, as well as the difference between controlled and uncontrolled components.
User input is crucial for all interactive web applications. React handles this input elegantly, using state
, props
, and hooks
. Let's construct a Greeting
function component that presents a dynamic message based on user input.
In this component, useState
is used to declare the state
variable name
. The name
stores the value of the input element and updates whenever the text input changes:
JavaScript1import React, { useState } from 'react'; 2 3function Greeting() { 4 const [name, setName] = useState(''); 5 6 return ( 7 <div> 8 <h1>Hello, {name}!</h1> 9 <input 10 type="text" 11 value={name} 12 onChange={(event) => setName(event.target.value)} // Updates `name` upon typing in the input 13 /> 14 </div> 15 ); 16}
Refs or references in React provide a way to access and interact with DOM nodes or React elements directly within your components. This is especially handy in cases where you want to change the child component without making use of props or triggering a re-render.
Refs are created by invoking the useRef
hook provided by React. Here's how we do it:
JavaScript1const myRef = useRef();
Notice that we call useRef()
without passing any arguments. This results in myRef.current
getting initialized with the value of null
. The current
property is mutable; it's created specifically for you to assign it a persistent value that doesn't trigger a re-render, thereby allowing the value to persist across renders.
Let’s see how the ref is used with an actual element in JSX by using the ref
attribute, which takes the ref created above as its value:
JavaScript1<input ref={myRef} type="text" />
The ref
attribute acts like a tether, linking the myRef
ref to the input field, hence allowing us detailed access to this specific instance of the input field across renders. It lets myRef.current
point to the corresponding DOM node, here an HTMLInputElement, providing a way to read from or write to it.
Following is a brief example:
JavaScript1import React, { useRef } from 'react'; 2 3function Greeting() { 4 const nameRef = useRef(); // nameRef.current is initialized as null 5 6 return ( 7 <div> 8 <h1>Hello, {nameRef.current && nameRef.current.value}!</h1> 9 <input ref={nameRef} type="text" /> {/* ties nameRef to the input field */} 10 </div> 11 ); 12}
As we can see, the text input is now linked with nameRef
. Although in this form React does not automatically capture and update its value, opening up interesting possibilities we'll look at next.
Controlled inputs are connected to React state, and they change when the state changes. Conversely, uncontrolled inputs store their state internally and are not controlled by React. Although the state is more commonly controlled by components, uncontrolled components are useful in some scenarios, such as file uploads.
React provides flexibility in how we can create components in terms of handling user input. Both controlled and uncontrolled components serve different purposes and are utilized based on the specific needs of your application.
When creating uncontrolled components, we let the form field keep track of its own value, rather than updating the value based on the application’s state. Here's an example of an uncontrolled component:
JavaScript1import React, { useRef } from "react"; 2 3function UncontrolledComponent() { 4 const inputRef = useRef(); // Creates a ref 5 6 function handleSubmit(e) { 7 e.preventDefault(); 8 alert(inputRef.current.value); // Reads directly from the DOM 9 } 10 11 return ( 12 <form onSubmit={handleSubmit}> 13 <input ref={inputRef} type="text" /> 14 <button type="submit">Submit</button> 15 </form> 16 ); 17}
In this case, inputRef.current
points directly to the input DOM element, enabling you to read its value directly.
When creating controlled components, we let React's state handle the input field’s value. Here’s an example of a controlled component:
JavaScript1import React, { useState } from "react"; 2 3function ControlledComponent() { 4 const [name, setName] = useState(''); // Creates a state variable 5 6 function handleSubmit(e) { 7 e.preventDefault(); 8 alert(name); 9 } 10 11 return ( 12 <form onSubmit={handleSubmit}> 13 <input 14 type="text" 15 value={name} 16 onChange={e => setName(e.target.value)} // Sets the state variable when the input changes 17 /> 18 <button type="submit">Submit</button> 19 </form> 20 ); 21}
In this case, the input field’s value is controlled by the name
state variable, and it updates via the onChange
handler.
Each of these methods has its own use case scenarios and can be useful in different situations. It's essential to understand both approaches, so you can be effective in managing data input and flow within your React applications.
Nested components allow us to break down components into smaller, more reusable parts. Various parent-child relationships exist in React. For instance, if People
is considered a parent component, Person
would be its child:
JavaScript1function Person({ name }) { 2 return <p>Hello, {name}!</p>; 3} 4 5function People() { 6 const names = ['Alice', 'Bob', 'Charlie']; 7 8 return ( 9 <div> 10 {names.map((name) => ( 11 <Person key={name} name={name} /> // Child components 12 ))} 13 </div> 14 ); 15}
Any changes in parent components will consequently affect their nested child components.
Congratulations on learning to handle user inputs in React functional components! We have covered state
, props
, refs
, hooks
, and the distinction between controlled and uncontrolled components.
Up next are the hands-on tasks for you to practice! Enjoy coding with React!