惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
Lohrmann on Cybersecurity
Martin Fowler
Martin Fowler
Engineering at Meta
Engineering at Meta
腾讯CDC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Azure Blog
Microsoft Azure Blog
G
Google Developers Blog
TaoSecurity Blog
TaoSecurity Blog
博客园_首页
Vercel News
Vercel News
Hugging Face - Blog
Hugging Face - Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Last Week in AI
Last Week in AI
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
The Exploit Database - CXSecurity.com
量子位
Project Zero
Project Zero
A
Arctic Wolf
小众软件
小众软件
NISL@THU
NISL@THU
C
CERT Recently Published Vulnerability Notes
有赞技术团队
有赞技术团队
MongoDB | Blog
MongoDB | Blog
博客园 - 聂微东
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
News and Events Feed by Topic
宝玉的分享
宝玉的分享
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Troy Hunt's Blog
P
Privacy & Cybersecurity Law Blog
Security Latest
Security Latest
B
Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
D
DataBreaches.Net
Schneier on Security
Schneier on Security
The Hacker News
The Hacker News
K
Kaspersky official blog
C
Check Point Blog
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Webroot Blog
Webroot Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
人人都是产品经理
人人都是产品经理
AI
AI
Cisco Talos Blog
Cisco Talos Blog
MyScale Blog
MyScale Blog
Cloudbric
Cloudbric
B
Blog RSS Feed
S
Schneier on Security
P
Palo Alto Networks Blog

Dmitri Pavlutin Blog

Pure Functions in JavaScript: A Beginner's Guide Record Type in TypeScript: A Quick Intro How to Write Comments in React: The Good, the Bad and the Ugly 4 Ways to Create an Enum in JavaScript React forwardRef(): How to Pass Refs to Child Components TypeScript Function Types: A Beginner's Guide How to Use v-model to Access Input Values in Vue Mastering Vue refs: From Zero to Hero Environment Variables in JavaScript: process.env 5 Must-Know Differences Between ref() and reactive() in Vue How to Destructure Props in Vue (Composition API) Triangulation in Test-Driven Development How to Use nextTick() in Vue Programming to Interface Vs to Implementation A Smarter JavaScript Mapper: array.flatMap() Array Grouping in JavaScript: Object.groupBy() How to Access ES Module Metadata using import.meta JSON Modules in JavaScript How to Trim Strings in JavaScript TypeScript Function Overloading How to Debounce and Throttle Callbacks in Vue How to Show/Hide Elements in Vue Sparse vs Dense Arrays in JavaScript How to Fill an Array with Initial Values in JavaScript Covariance and Contravariance in TypeScript What are Higher-Order Functions in JavaScript? How to Use TypeScript with React Components Index Signatures in TypeScript How to Use React useReducer() Hook unknown vs any in TypeScript A Guide to React Context and useContext() Hook How to Use Promise.any() 2 Ways to Remove a Property from an Object in JavaScript 'return await promise' vs 'return promise' in JavaScript How to Use Promise.allSettled() How to Use fetch() with JSON JavaScript Promises: then(f,f) vs then(f).catch(f) What is a Promise in JavaScript? How to Use Promise.all() A Simple Guide to Component Props in React Don't Stop Me Now: How to Use React useTransition() hook A Simple Explanation of JavaScript Variables: const, let, var ES Modules Dynamic Import How to Memoize with React.useMemo() How to Cleanup Async Effects in React Why Math.max() Without Arguments Returns -Infinity How to Debounce and Throttle Callbacks in React Don't Confuse Function Expressions and Function Declarations in JavaScript How to Use ES Modules in Node.js Solving a Mystery Behavior of parseInt() in JavaScript How to Use Array Reduce Method in JavaScript 3 Ways to Merge Arrays in JavaScript A Guide to Jotai: the Minimalist React State Management Library The Difference Between Values and References in JavaScript How to Implement a Queue in JavaScript A Helpful Algorithm to Determine "this" value in JavaScript React useRef() Hook Explained in 3 Steps 7 Interview Questions on "this" keyword in JavaScript. Can You Answer Them? How to Greatly Enhance fetch() with the Decorator Pattern 7 Interview Questions on JavaScript Closures. Can You Answer Them? What's a Method in JavaScript? array.sort() Does Not Simply Sort Numbers in JavaScript How to Solve the Infinite Loop of React.useEffect() The New Array Method You'll Enjoy: array.at(index) What's the Difference between DOM Node and Element? Why Promises Are Faster Than setTimeout()? Everything About Callback Functions in JavaScript How React Updates State 5 Mistakes to Avoid When Using React Hooks 5 Best Practices to Write Quality JavaScript Variables Type checking in JavaScript: typeof and instanceof operators 3 Ways to Check if a Variable is Defined in JavaScript React Forms Tutorial: Access Input Values, Validate, Submit Forms Prototypal Inheritance in JavaScript How to Timeout a fetch() Request How to Learn JavaScript If You're a Beginner A Simple Explanation of React.useEffect() A Simple Explanation of JavaScript Iterators Everything about null in JavaScript How to Use Fetch with async/await Getting Started with Arrow Functions in JavaScript An Interesting Explanation of async/await in JavaScript Front-end Architecture: Stable and Volatile Dependencies Is it Safe to Compare JavaScript Strings? How to Access Object's Keys, Values, and Entries in JavaScript What Actually is a String in JavaScript? 3 Ways to Shallow Clone Objects in JavaScript (w/ bonuses) Checking if an Array Contains a Value in JavaScript JavaScript Event Delegation: A Beginner's Guide How to Parse URL in JavaScript: hostname, pathname, query, hash 3 Ways to Detect an Array in JavaScript How to Get the Screen, Window, and Web Page Sizes in JavaScript 3 Ways to Check If an Object Has a Property/Key in JavaScript How to Compare Objects in JavaScript Object.is() vs Strict Equality Operator in JavaScript Own and Inherited Properties in JavaScript 5 Differences Between Arrow and Regular Functions How to Use Object Destructuring in JavaScript Your Guide to React.useCallback() 5 JavaScript Scope Gotchas
How to Use React Controlled Inputs
Dmitri Pavlutin · 2020-09-29 · via Dmitri Pavlutin Blog

React offers 2 approaches to access the value of an input field: using a controlled or uncontrolled inputs techniques. I prefer the controlled because you read and set the input value through the component's state.

In this post, you'll read how to implement controlled inputs using React hooks.

Table of Contents

  • 1. The controlled input
  • 2. Controlling multiple inputs
  • 3. The state as the source of truth
  • 4. Debouncing the controlled input
  • 5. Summary

1. The controlled input

Let's say you have a simple text input field, and you'd like to access its value:


import { useState } from 'react';

function MyControlledInput() {

const [value, setValue] = useState('');

const onChange = (event) => {

setValue(event.target.value);

};

return (

<>

<div>Input value: {value}</div>

<input value={value} onChange={onChange} />

</>

);

}


Open the demo.

Open the demo and type into the input field. value state variable contains the value entered into the input field that is updated each time you type into the input field.

The input field is controlled because React sets its value from the state <input value={value} ... />. When the user types into the input field, the onChange handler updates the state with the input’s value accessed from the event object: event.target.value.

React Controlled Form Input Data Flow

value state variable is the source of truth. Each time you need to access the input value — just read value state variable.

To resume, the controlled input technique requires 3 steps:

  1. Define the state to hold the input value:


const [value, setValue] = useState('')


  1. Create the event handler that updates the state when the input value changes:


const onChange = event => setValue(event.target.value)


  1. Assign the input field with the state value and attach the event handler:


<input type="text" value={value} onChange={onChange} />


The controlled components approach can help you access the value of any input type: textual inputs, textareas, select fields.

In case of a checkbox, however, you have to use checked prop instead of value:


<input checked={value} onChange={onChange} type="checkbox" />


2. Controlling multiple inputs

Often you have to deal with forms that contain multiple input fields. In such a case, instead of creating many state variables for each input field, I find it useful to use a single object to keep the state of the input fields.

Each input field has a corresponding property in the state object.

For example, let's use an object values having the properties first and last to hold the information of first and last name input fields.


import { useState } from 'react';

export default function MyControlledInputs() {

const [values, setValues] = useState({ first: '', last: '' });

const getHandler = (name) => {

return (event) => {

setValues({ ...values, [name]: event.target.value });

};

};

return (

<>

<div>Name: {values.first} {values.last}</div>

<input value={values.first} onChange={getHandler('first')} />

<input value={values.last} onChange={getHandler('last')} />

</>

);

}


Edit on CodeSandbox

The state of the component is now an object values. That's usually shorter than creating state variables for each input field.

getHandler is a factory function that returns event handlers to update the property supplied as an argument. The returned event handler is assigned to onChange prop of the input field.

The benefit of such a design is that you can handle a lot of input fields without adding too much boilerplate code.

3. The state as the source of truth

Let's see a more complex example. A web page consists of a list of employees' names. You need to add an input field, and when the user types into this field, the employees' list is filtered by name.

That's a good scenario to use a controlled input. Here's a possible implementation:


function FilteredEmployeesList({ employees }) {

const [query, setQuery] = useState('');

const onChange = event => setQuery(event.target.value);

const filteredEmployees = employees.filter(name => {

return name.toLowerCase().includes(query.toLowerCase());

});

return (

<div>

<h2>Employees List</h2>

<input

type="text"

value={query}

onChange={onChange}

/>

<div className="list">

{filteredEmployees.map(name => <div>{name}</div>)}

</div>

</div>

);

}


Open the demo.

Open the demo and enter a query into the input field. The list of employees is filtered.

What's important is that query state variable is the source of truth for the value entered in the input field. You use it inside employees.filter() to filter the list of employees: name.toLowerCase().includes(query).

4. Debouncing the controlled input

In the previous implementation, as soon as you type a character into the input field, the list gets filtered instantly. That's not always convenient because it distracts the user when typing the query.

Let's improve the user experience with debouncing: filter the list with a delay of 400 ms after the last input change.

Let's see a possible implementation of a debounced controlled input:


import { useDebouncedValue } from './useDebouncedValue';

function FilteredEmployeesList({ employees }) {

const [query, setQuery] = useState('');

const debouncedQuery = useDebouncedValue(query, 400);

const onChange = event => setQuery(event.target.value);

const filteredEmployees = employees.filter(name => {

return name.toLowerCase().includes(debouncedQuery.toLowerCase());

});

return (

<div>

<h2>Employees List</h2>

<input

type="text"

value={query}

onChange={onChange}

/>

<div className="list">

{filteredEmployees.map(name => <div>{name}</div>)}

</div>

</div>

);

}


Open the demo.

Open the demo and enter a query into the input field. The employees' list doesn't filter while you type, but after passing 400ms after the latest keypress.

The new state value debouncedQuery value is managed by a specialized hook that implements debouncing: useDebouncedValue(query, 400) . debouncedQuery state value is used to filter the employees' list and is derived from the input value state.

Here's the implementation of useDebouncedValue():


export function useDebouncedValue(value, wait) {

const [debouncedValue, setDebouncedValue] = useState(value);

useEffect(() => {

const id = setTimeout(() => setDebouncedValue(value), wait);

return () => clearTimeout(id);

}, [value]);

return debouncedValue;

}


In a few words, here's how it works.

First, the useDebouncedValue() hook creates a new state derived from the main state.

Then, useEffect() updates after wait delay the debouncedValue state when the main value state changes.

5. Summary

The controlled input is a convenient technique to access values of input fields in React.

Setting up a controlled input requires 3 steps:

  1. Create the state to hold the input value: const [val, setVal] = useState('')
  • Define the event handler to update the state when the user types into the input: onChange = event => setVal(event.target.value)
  • Attach the event handler and set value attribute on the input field: <input onChange={onChange} value={val} />.

Debouncing of the input value state requires creating a new derived state using the specialized hook debouncedQuery = useDebouncedValue(value, wait).

Do you have any question regrading controlled inputs?