skip to Main Content

I am creating a form in React that uses dynamically added fieldsets for contacts that I am adding through using state. These fieldsets have a button to remove the fieldset if the user wishes to. However when I click the remove button and display the state value, I am getting a different albeit consistent result, which when filtering is not giving proper results.

Here are bits of the code I am using:

const [insertContactForm, setInsertContactForm] = useState([]);
const [position, setPosition] = useState(0);

then to add the form component when the ‘add contact’ button is clicked:

const handleAddContactForm = (e) => {
        e.preventDefault();
        setPosition(position + 1);
        setInsertContactForm([...insertContactForm, <div key={position}><button onClick={(e) => {handleContactFormRemove(e, position)}}>-</button><ContactForm contactNumber={position} /></div>]);
    }

To see what data was passed to the remove contact form function:

const handleContactFormRemove = (e, position) => {
        e.preventDefault();
        console.log(position);
        console.log(insertContactForm)
    }

When I click on each remove button, I am getting an array returned that differs from the current state – for example, if I insert three contact forms and click on the first delete button, I am getting an empty array for the state; if I click on the second delete button, I get an array with the prior element, and on the third it returns an array with the two prior elements. How do I make sure I am getting the current state when I click the delete button? The position state always displays correctly, just FYI.

Thanks!

2

Answers


  1. React State change is async so not necessarily you will get the state value immediately.
    You can make use of useEffect with dependency to check if value change and do the operation

    Login or Signup to reply.
  2. This line

    setInsertContactForm([...insertContactForm, (
      <div key={position}>
        <button onClick={(e) => {handleContactFormRemove(e, position)}}>-</button>
        <ContactForm contactNumber={position} />
      </div>
    )]);
    

    will add the elements to state as expected, but the button’s click handler won’t ever be updated. It’s set to the handleContactFormRemove function that is in scope within that specific render. In subsequent renders that function will be a new function that captures the new state, but it’s still the old version of that function that runs when you click the button, because that’s the version that was added as the onClick handler. That old version of the function captured the variables it had when it was defined, not the new versions of them that exist when the function reruns.


    The simplest way around this would probably be to avoid using the buttons/ContactForms as state variables, and instead use an array of positions (in addition to the existing position state that would be used to reference the next value and avoid duplicates). Then you can use that array to create the buttons and ContactForms.

    const [nextPosition, setNextPosition] = useState(0);
    const [positions, setPositions] = useState([]);
    
    const handleAddContactForm = (e) => {
      e.preventDefault();
      setNextPosition(nextPosition + 1);
      setPositions([...positions, nextPosition]);
    }
    
    const handleContactFormRemove = (e, positionToRemove) => {
      e.preventDefault();
      console.log(positionToRemove);
      console.log(positions)
    }
    
    return (
      <div>
        <button onClick={handleAddContactForm}>+</button>
    
        {positions.map((position) => (
          <div key={position}>
            <button onClick={(e) => {handleContactFormRemove(e, position)}}>-</button>
            <ContactForm contactNumber={position} />
          </div>
        ))}
      </div>
    )
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search