1

I am making a single object out of three independently populated subsections of a form. They are independently populated because the data comes from three different sources:

1) backend api for name and address 2) third party api for telephone number 3) user executing onChange on other fields in the form

what I have noticed is if I submit the form with onChange being the last function executed, ie if entering a note or updating an email address, then the other two elements have some of the data removed specifically the first field of each source.

I have remedied this by creating an effect that basically runs a form control operation (basically resets the phone number) and doing this fixes the problem, but clearly I would not like to not have to rely on a a useState method and call it something its not for the sake of fixing a problem I don't understand. Here is some code.

Thanks!

const leadContext = useContext(LeadContext);

  const { clearLiens, lien, setLien, letCall, number, clearNumber, addLead, postLogics } = leadContext;



  useEffect(() => {

    if (lien !== null) {

      setRecord(lien);

    }else {
      setRecord({
        name: '',
        address:'',
        city:'',
        state:'',
        zip:'',
        plaintiff:'',
        amount:'' 
      });
    }
  }, [lien, leadContext]);

  useEffect (()=>{ 

    if(number !== null){

      setCall({phone:number});

    }else {
      setCall({phone:''});
    }
  },[number, leadContext]);

  const [ record, setRecord ] = useState({
    name: '',
    address:'',
    city:'',
    state:'',
    zip:'',
    plaintiff:'',
    amount:'',
    lienid:''
  });

  const [ call, setCall ] = useState({
        phone: ''});


  const [ open, setOpen ] = useState({
       email:'',
       lexId:'',
       compliant:'filed',
       filingStatus:'married',
       cpa: 'cpa',
       ssn:'',
       noteText:''
  });



  const onChange = e => {
    setRecord({...name, address, city, state, zip, plaintiff, amount, [e.target.name]: e.target.value });
    setCall({...phone, [e.target.name]: e.target.value });
    setOpen({...email, lexId, compliant, filingStatus, cpa, ssn, noteText, [e.target.name]: e.target.value});
  }

  const { name, address, city, state, zip, plaintiff, amount, lienid } = record
  const { phone } = call
  const { email, lexId, compliant, filingStatus, cpa, ssn, noteText } = open



  const lead = {phone, name, address, city, state, zip, plaintiff, amount, lienid, email, lexId, compliant, filingStatus, cpa, ssn, noteText }


  const clearLead = () => {
    clearNumber();
    setLien('');
    setRecord({
      name: '',
      address:'',
      city:'',
      state:'',
      zip:'',
      plaintiff:'',
      amount:'',
    });
    setCall({
      phone: ''});

    setOpen({
        email:'',
        lexId:'',
        compliant:'filed',
        filingStatus:'m',
        cpa: 'cpa',
        noteText:'',
        ssn:''
   });  

  }

  const onSubmit = e => {
      e.preventDefault();
      addLead(lead);
      clearAll();
    };  

  const clearAll = () => {
      clearLiens();
      clearLead();
    };

  const onClick = e => {
    letCall(number);
  }

the letCall(number) is my hot fix of basically calling set state on one of the form fields. I cannot stack this into my on submit either, so it has to be done as a separate function.

const addLead = async lead => {
    const config = {
      headers: {
        'Content-Type': 'application/json'
      }
    };

      const { phone, name, address, city, state, zip, plaintiff, amount, lienid, email, lexId, compliant, filingStatus, cpa, ssn, noteText } = lead


      const noteId = uuidv4();

      const notes = [{ id : noteId,
                       note : noteText,
                       notePostedBy: ''
                    }]  

      const steve = {phone, name, address, city, state, zip, plaintiff, amount, lienid, email, lexId, compliant, filingStatus, cpa, ssn, notes }
      console.log(lead,'1');
      console.log(steve,'1');
      const res = await axios.post('/api/leads/', steve, config);

      dispatch({
        type: POST_LEAD,
        payload: res.data
      });

  };

1 Answer 1

1

Looks like this has to do with the way you update your state values in onChange. Specifically, you write:

setRecord({...name, address, city, state, zip, plaintiff, amount, [e.target.name]: e.target.value });

But since name is not spreadable, it becomes an empty value, so the updated record state will not have a value for name (unless name was the changed input).

To fix this you can simplify your updating with:

const onChange = e => {
    setRecord(prev => ({...prev, [e.target.name]: e.target.value}));
    setCall(prev => ({...prev, [e.target.name]: e.target.value}));
    setOpen(prev => ({...prev, [e.target.name]: e.target.value}));
}

However you probably also want to add some sort of check to update the correct state object so that the keys don't get put into all state objects. Something like:

const onChange = e => {
    if (Object.keys(record).includes(e.target.name) {
        setRecord(prev => ({...prev, [e.target.name]: e.target.value}));
    }
    // and so on...
}

Edit:

When using the callback version of set[State], the event will become null since the callback is called asynchronously (specifically at another time). To fix this you can either use:

e.persist();

at the top of the onChange function (however, probably not optimal in this case).

Or get name and value from e.target and passing them directly to the callback. For example:

const onChange = e => {
    const { name, value } = e.target;

    if (Object.keys(record).includes(name) {
        setRecord(prev => ({...prev, [name]: value}));
    }
    // and so on...
}

This is probably the most appropriate solution here.

Sign up to request clarification or add additional context in comments.

3 Comments

index.js:1406 Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property target on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist(). Seeinformation. LeadForm.js:73 Uncaught TypeError: Cannot read property 'name' of null at LeadForm.js:73 at basicStateReducer
ah yes, can be fixed by either calling e.persist() or getting the name and value out of the event's target at the top of onChange and then using those directly rather than through e.target. Will update answer.
how to donate to stack over flow <3

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.