Como Você Atualiza Objetos no Estado?
Atualizar objetos no estado em React pode ser complicado se você estiver acostumado a alterar diretamente os valores das propriedades do objeto.
React trata o estado como imutável, o que significa que você não deve modificá-lo diretamente.
Vamos ver o que acontece se você tentar alterar objetos no estado do React diretamente e depois mergulhar na maneira correta de fazer isso.
Vamos supor que você tenha um objeto no estado do seu componente que representa o perfil de um usuário e queira que o usuário atualize sua idade:
import { useState } from "react";
function Profile() {
const [user, setUser] = useState({
name: "John Doe",
age: 31,
city: "LA",
});
// Change user age directly
const handleAgeChange = (e) => {
user.age = e.target.value;
console.log(user);
};
return (
<div>
<h1>User Profile</h1>
<p>Name: {user.name}</p>
<p>Age: {user.age}</p>
<p>City: {user.city}</p>
<h2>Update User Age </h2>
<input type="number" value={user.age} onChange={handleAgeChange} />
</div>
);
}
export default Profile;
Este código não funcionará porque você está modificando diretamente a propriedade user.age.
Embora console.log(user) mostre a nova idade no console, o React não irá re-renderizar o componente para exibí-la na interface do usuário porque você não usou a função setter, setUser.
Para atualizar um objeto diretamente no estado, você precisa usar a função setter para criar um novo objeto com o valor atualizado. Por exemplo:
const handleAgeChange = (e) => {
setUser({
age: e.target.value,
});
};
Isso funciona. Mas se você olhar a página agora, a idade do usuário é atualizada, mas os valores para o nome e a cidade são perdidos.
Isso ocorre porque o novo objeto que você passou para a função setter continha apenas um par chave/valor para age.
Para evitar que isso aconteça, você pode copiar o objeto existente primeiro e depois atualizar apenas a propriedade que deseja atualizar, neste caso, age.
Para fazer isso, você pode passar uma função especial chamada função atualizadora para sua função setter, setUser. A função atualizadora recebe o estado pendente como argumento, aqui chamado de prevUser, e deve retornar o próximo estado:
const handleAgeChange = (e) => {
setUser((prevUser) => {
const updatedUser = { ...prevUser, age: e.target.value };
console.log('Previous State:', prevUser);
console.log('Updated State:', updatedUser);
return updatedUser;
});
};
Como você pode ver, criamos um novo objeto de usuário chamado updatedUser usando a sintaxe spread para copiar o objeto de usuário pendente, ...prevUser. Atualizamos então a idade com base na entrada do formulário e retornamos updatedUser no final da função como o próximo estado.
Agora seu projeto funciona como esperado e as atualizações no input de idade não afetam o nome do usuário ou o nome da cidade. Você também pode ver os estados anterior e atualizado no console.
Esta é a maneira ideal de atualizar um objeto no estado, especialmente quando você não está atualizando todas as propriedades.
Para atualizar as propriedades restantes name e city, você pode escrevê-las como funções de configuração separadas e conectá-las às suas respectivas entradas:
const handleNameChange = (e) => {
setUser((prevUser) => ({
...prevUser,
name: e.target.value,
}));
};
const handleCityChange = (e) => {
setUser((prevUser) => ({
...prevUser,
city: e.target.value,
}));
};
Ou você pode combiná-los em uma única função setter assim:
const handleChange = (e) => {
const { name, value } = e.target;
setUser((prevUser) => ({
...prevUser,
[name]: value,
}));
};
Para que isso funcione, cada campo de entrada precisa ter um atributo name.
Aqui está o código completo agora:
import { useState } from "react";
function Profile() {
const [user, setUser] = useState({ name: "John Doe", age: 31, city: "LA" });
const handleChange = (e) => {
const { name, value } = e.target;
setUser((prevUser) => ({...prevUser, [name]: value}));
};
return (
<div>
<h1>User Profile</h1>
<p>Name: {user.name}</p>
<p>Age: {user.age}</p>
<p>City: {user.city}</p>
<h2>Update User Age </h2>
<input type="number" name="age" value={user.age} onChange={handleChange} />
<h2>Update User Name </h2>
<input type="text" name="name" value={user.name} onChange={handleChange} />
<h2>Update User City </h2>
<input type="text" name="city" value={user.city} onChange={handleChange} />
</div>
);
}
export default Profile;Este módulo não possui perguntas. Marque como concluído.