Get rid of nested ifs and else I have a contact model, on change I set the state of the contact object, how can I make the below function more readable?
The address field is different because it's an object: ['address', 'city', 'state', 'zip']
  const onFieldChange = (
    key,
    index = 0,
    isMulti = false,
    isAddress = false
  ) =&gt; event =&gt; {
    const value = event.target.value
    const updatedContact = {...contact}
    if (!isMulti) {
      updatedContact[key] = value
      if (
        key === 'type' &amp;&amp;
        value === 'Individual' &amp;&amp;
        contact.entityFormationDate
      ) {
        delete updatedContact.entityFormationDate
      }
    } else {
      const keyInternal = isAddress ? key : 'value'
      key = isAddress ? 'addresses' : key
      updatedContact[key][index][keyInternal] = value
    }
    setContact(updatedContact)
  }
Code readability is a subjective quantity, however it is still considered as on-topic here at Code-Review.
General readability points
Note that code in isolation is must rely on presumptions. The scope, naming, and missing defines may force some of the following points to change if known.

Use simplest statements possible. For example the statement if (!isMulti) { can be simplified to if (isMulti) { and swapping the code blocks.

Avoid breaking lines unless they extend past the right of screen.
Some people use 80 columns (a little last century in my book (word warp is standard in IDE's these days)), 120 or even 160 will be readable in all but the smallest of devices.

Avoid repetition. You test isAddress twice within the listener. This can be done once outside the returned function. See rewrite.
This may not be considered a readability issue, but part of good code readability is clearly showing intent.
To read the two lines testing isAddress I immediately questioned why in the event? This is already known? I had to check as your intent was muddied.

The function onFieldChange is not an event listener, it returns a listener. The the prefixed on obfuscates its usage.
The name would be better as just createFieldChangeEvent, fieldChangeListener, or fieldChange depending on the functions scope.

Semicolons go a long way to improve readability, especially for coders that are swapping between C like languages.

The string literals should be constants, however without the full scope and usage of these strings it is hard to define where and how to declare. So I leave them as is (apart from changing to double quotes)


Rewrite
Two rewrites to contrast the subjective nature of readability.
General rewrite
Using the above points the code can be rewritten as
const fieldChangeListener = (key,  index = 0, isMulti = false, isAddress = false) =&gt; {
  const [field, internalKey] = isAddress ? [key, &quot;addresses&quot;] : [&quot;value&quot;, key];
  const isTypeKey = key === &quot;type&quot;;
  return event =&gt; {
    const value = event.target.value;
    const updated = {...contact};
    if (isMulti) {
      updated[field][index][internalKey] = value;
    } else {
      updated[key] = value;
      const isTypeIndividual = value === &quot;Individual&quot; &amp;&amp; isTypeKey;
      if (isTypeIndividual &amp;&amp; contact.entityFormationDate) {
        delete updated.entityFormationDate;
      }
    }
    setContact(updated);
  }
}

Is it more readable. We that depends on the readers level of experience and skill.
Compact rewrite
Personally I would have compacted the code further as its the total quantity (lines of code) that make code navigation the crucial readability factor. Code is seldom read in isolation.
const fieldChange = (name,  idx = 0, isMulti = false, isAddress = false) =&gt; {
  const [internal, fieldName] = isAddress ? [&quot;addresses&quot;, name] : [name, &quot;value&quot;];
  const isType = name === &quot;type&quot;;
  return event =&gt; {
    const [updated, value] = [{...contact}, event.target.value];
    if (isMulti) {
      updated[fieldName][idx][internal] = value;
    } else {
      const canDelete = (updated[name] = value) === &quot;Individual&quot; &amp;&amp; isType;
      canDelete &amp;&amp; contact.entityFormationDate &amp;&amp; (delete updated.entityFormationDate);
    }
    setContact(updated);
  }
}

Defined readability
Code readability is very dependent on code standards used in projects. Standards must be defined in writing.
This is a document that all project coders should be thoroughly versed in and defines the styles, naming, layout, language features, etc... used and not to use in each project.
It can be argued that a comprehensive code standards document makes it impossible to write unreadable code.
To start a project without a standards document has already failed the first rule of readability. &quot;Subjectivity is unreliable&quot;.
Example standards (as un-categorized points) I used for &quot;Compact rewrite&quot;

Fields to have names not keys.
index is always written idx.
Short circuited end clauses must be grouped.
Single line expression with multiple assignments must group each assignment.
Use semicolons.
Prefer declarations using destructuring assignments over multi-line declarations.