В предыдущей статье я рассказал, как хранить и обновлять массивы в useState hook. В этой статье мы рассмотрим, как изменять хранимые объекты с помощью useState hook.
Настройка проекта
Создайте проект react с помощью следующей команды:
npx create-react-app react-usestate-object
Обновление объекта state
Создадим 2 поля с firstName
и lastName
:
import { useState } from "react"
function App() {
const [name, setName] = useState({ firstName: "", lastName: "" })
return (
<div className="App">
<div>
<label htmlFor="firstName">First Name: </label>
<input
type="text"
name="firstName"
id="firstName"
value={name.firstName}
/>
</div>
<div>
<label htmlFor="lastName">Last Name: </label>
<input
type="text"
name="lastName"
id="lastName"
value={name.lastName}
/>
</div>
<div>
Name is: {name.firstName} {name.lastName}
</div>
</div>
)
}
export default App
Здесь у нас есть объект name
в качестве локального состояния для хранения firstName
и lastName
. В настоящее время эти поля доступны только для чтения.
Давайте добавим функции onChange
к этим полям и будем обновлять объект state, когда пользователи вводят текст в поле ввода:
import { useState } from "react"
function App() {
const [name, setName] = useState({ firstName: "", lastName: "" })
const setFirstName = e => {
setName(existingValues => ({
// Retain the existing values
...existingValues,
// update the firstName
firstName: e.target.value,
}))
}
const setLastName = e => {
setName(existingValues => ({
// Retain the existing values
...existingValues,
// update the lastName
lastName: e.target.value,
}))
}
return (
<div className="App">
<div>
<label htmlFor="firstName">First Name: </label>
<input
type="text"
name="firstName"
id="firstName"
value={name.firstName}
onChange={setFirstName}
/>
</div>
<div>
<label htmlFor="lastName">Last Name: </label>
<input
type="text"
name="lastName"
id="lastName"
value={name.lastName}
onChange={setLastName}
/>
</div>
<div>
Name is: {name.firstName} {name.lastName}
</div>
</div>
)
}
export default App
Здесь мы используем оператор spread, чтобы сохранить существующие значения и обновить только необходимые.
Объединение обновления в одну функцию
Поскольку функциональность обновления обоих полей одинакова, мы можем написать общую функцию обновления, как показано ниже:
import { useState } from "react"
function App() {
const [name, setName] = useState({ firstName: "", lastName: "" })
const updateName = e => {
const fieldName = e.target.name
setName(existingValues => ({
// Retain the existing values
...existingValues,
// update the current field
[fieldName]: e.target.value,
}))
}
return (
<div className="App">
<div>
<label htmlFor="firstName">First Name: </label>
<input
type="text"
name="firstName"
id="firstName"
value={name.firstName}
onChange={updateName}
/>
</div>
<div>
<label htmlFor="lastName">Last Name: </label>
<input
type="text"
name="lastName"
id="lastName"
value={name.lastName}
onChange={updateName}
/>
</div>
<div>
Name is: {name.firstName} {name.lastName}
</div>
</div>
)
}
export default App
Здесь мы использовали нотацию [variableContainingPropertyName]
для установки значения соответствующего объекта.
Если полей много, можно воспользоваться хуком useReducer,
что также помогает при валидации формы.