So I’ve spent dozens of hours wondering why this is going on at this point, and I’ve looked into a few different solutions.
I’m pretty sure it doesn’t have to do with any lifecycle methods or asynchronous issues of React’s setState function, though I've investigated thoroughly.
I’m pretty sure it doesn’t have to do with value/reference issues of tempState actually mutating state, because I’m using lodash to deepClone the state object, though this was a previous issue.
I suspect it has to do with setState’s shallow merge, but I cannot for the life of me figure out why.
Essentially, I thought that this code should only change the typeAheadOptions array to change the hostshow values to Various Shows, but it is mutating the state as well, and not even in the same way. The state isn't even the same shape as the the typeAheadOptions-- it is deeper with a couple other layers in it.
At this point, I might rebuild this with Redux and ImmutableJS, but now I really need to understand why this is happening, because it is making me slightly crazy. And now I've read suggestions to keep your state objects as flat as possible, and I think I understand why now.
Here’s the snipped state with just the relevant bits:
this.state = {
  showByName: false,
  showByShow: true,
  resources: [
    {
      show: "TED Radio Hour",
      showurl: TEDRadioHour,
      hosts: [
        {
          firstName: "Guy",
          lastName: "Raz",
          personurl: GuyRaz,
          hostshow: "TED Radio Hour"
        }
      ]
    },
    {
      show: "Radiolab",
      showurl: Radiolab,
      hosts: [
        {
          firstName: "Jad",
          lastName: "Abumrad",
          personurl: JadAbumrad,
          hostshow: "Radiolab"
        },
        {
          firstName: "Robert",
          lastName: "Krulwich",
          personurl: RobertKrulwich,
          hostshow: "Radiolab"
        }
      ]
    },
    {
      show: "How I Built This",
      showurl: HowIBuiltThis,
      hosts: [
        {
          firstName: "Guy",
          lastName: "Raz",
          personurl: GuyRaz,
          hostshow: "How I Built This"
        }
      ]
    },
    {
      show: "Radiolab Presents: More Perfect",
      showurl: RadiolabPresentsMorePerfect,
      hosts: [
        {
          firstName: "Jad",
          lastName: "Abumrad",
          personurl: JadAbumrad,
          hostshow: "Radiolab Presents: More Perfect"
        }
      ]
    }
  ],
  contentToRender: [],
  typeAheadOptions: [],
  selected: [],
  duplicateHostIndices: []
}
}
And here are the functions:
showByName() {
 const tempState = _.cloneDeep(this.state);
 tempState.showByName = true;
 tempState.showByShow = false;
 tempState.selected.length = 0;
 this.alphabetizeHostList(tempState);
}
alphabetizeHostList(tempState) { // sorting state so that results are alphabetical
 tempState.typeAheadOptions.length = 0;  // clear typeAhead options
 tempState.resources.forEach((resource, index) => {
   resource.hosts.forEach((host, index) => {
     tempState.typeAheadOptions.push(host);
     tempState.typeAheadOptions.sort(function(a, b) {  // sorting function
      var nameA = a.firstName.toUpperCase(); // ignore upper and lowercase
      var nameB = b.firstName.toUpperCase(); // ignore upper and lowercase
      if (nameA < nameB) {
        return -1;
      }
      if (nameA > nameB) {
        return 1;
      }
      // names must be equal
      return 0;
     });
   })
 })
 this.populateDuplicateHostIndices(tempState);
}
populateDuplicateHostIndices(tempState) { // removes duplicates by first and last name for instances like Guy Raz and Jad Abumrad
 let duplicateHostIndices = tempState.duplicateHostIndices;
 duplicateHostIndices.length = 0;
 let options = tempState.typeAheadOptions;
 let length = options.length;
 let i = 1;
 if (length > 1 && tempState.showByName === true) {
  for (i; i < length; i++) {  // iterates over the hosts and finds duplicates by first and last name
     if ((options[i - 1].firstName === options[i].firstName) && (options[i - 1].lastName === options[i].lastName)) {
      duplicateHostIndices.push(i);
     }
   }
 }
 this.removeDuplicateHosts(tempState, duplicateHostIndices);
}
 removeDuplicateHosts(tempState, duplicateHostIndices) {
  if (duplicateHostIndices.length > 0) {
   duplicateHostIndices.sort().reverse();  // if we didn't sort and reverse, we would remove the 1st host and the index of the rest would be off and we would remove them
   duplicateHostIndices.forEach((element) => {
    const previousElement = (element - 1);
    tempState.typeAheadOptions[(previousElement)].hostshow = "Various Shows";
    tempState.typeAheadOptions.splice(element, 1);
   });
 }
 this.pullContentToRenderFromTypeAheadList(tempState);
}
pullContentToRenderFromTypeAheadList(tempState) {
 tempState.contentToRender = _.cloneDeep(tempState.typeAheadOptions); // separates out content that renders from list that TypeAhead pulls from
 this.setState(tempState);
}
