Rodrigo Assis Neves
Rodrigo Assis Neves

Reputation: 150

React map doesn't re-render as state changes

Could you help me with this please guys? I'm mapping this emails state but when I remove an email from the array in handleDelete the map doesn't re-render. When I console.log(emails) it's right, the email is removed correctly.

import { TextField, Chip, Avatar } from "@material-ui/core";
import React, { useState } from "react";
import "./Email.css";


export default function Email() {
   const [value, setValue] = useState<string>();
   const [emails, setEmails] = useState<string[]>([]);
   
   function onTextChange(e: any) {
      setValue(e.target.value.replace(" ", ""));
      if (value?.includes(",")) {
         let separated = e.target.value.split(",");
         const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
         const newEmails = separated.filter((val: any) => re.test(val));

         if (newEmails[0] !== undefined) {
            emails.push(newEmails[0]);
            setEmails(emails);
            console.log(emails);
         }

         setValue("");
      }
   }

   function handleDelete(email: string) {
      const index = emails.indexOf(email);
      if (index > -1) {
         setEmails(emails.splice(index, 1));
         console.log(email, "removed");
         console.log('new list',  emails)
      }
   }

   return (
      <div>
         <TextField
            value={value || ""}
            variant='outlined'
            onChange={onTextChange}
            id='textInput'
            InputProps={{
               startAdornment: (
                  <div style={{ top: "50%" }}>
                     {emails.map((email: any) => (
                        <Chip
                           label={email}
                           key={email}
                           avatar={<Avatar>{email[0].toUpperCase()}</Avatar>}
                           onDelete={() => handleDelete(email)}
                           style={{ display: "-webkit-inline-box" }}
                        />
                     ))}
                  </div>
               ),
            }}
         />
      </div>
   );
}

Upvotes: 3

Views: 2756

Answers (2)

user14103024
user14103024

Reputation:

Yes, I have met a similar problem before. First, it's because the "emails" variable is not changed. So I mean you call emails.splice function but the email variable not changed. You should create new array variable and set the changed value into it. Only that React state change listener can understand "emails" value changed so "I should render function again..".

function handleDelete(email: string) {
  const newEmails = [...emails];
  const index = newEmails.indexOf(email);
  if (index > -1) {
     setEmails(newEmails.splice(index, 1));
  }

}

Upvotes: 0

topched
topched

Reputation: 765

The issue is this line setEmails(emails.splice(index, 1)); Splice just changes the array in place so the memory location doesn't change for the array, so react doesnt see a change.

You want something like this setEmail(prevEmails => prevEmails.filter(e => e !== email))

Upvotes: 5

Related Questions