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.