Home > database >  React DOM not re-rendering after state change of array property
React DOM not re-rendering after state change of array property

Time:04-29

I do understand that this problem is very common and most people might find this as a duplicate but I am at my wits end and that is why I am here.

I have a React component called App is a functional component.

Start of App component

function App() {
  
  const [results, setResults] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [name, setName] = useState('');
  const [isNameSelected, setIsNameSelected] = useState(false);
  ...

There is a child component which is acting erratically at the moment and it is part of the return components of the App function.

Section of Code in return statement of the App component:

<ListGroup className="typeahead-list-group">
  {!isNameSelected &&
     results.length > 0 &&
     results.map((result: Result) => (
       <ListGroupItem
         key={result.cik}
         className="typeahead-list-group-item"
         onClick={() => onNameSelected(result)}
       >
         {result.cik   ' | '   result.name}
       </ListGroupItem>
     ))}
</ListGroup>

A change to to results is handled by the component FormControl's onChange function here also part of the return statement of App:

<FormControl
  placeholder="Entity/CIK"
  id="searchInput"
  type="text"
  autoComplete="off"
  onChange={handleInputChange}
  value={name}
/>

handleInputChange is defined in App function as:

const handleInputChange = (e: any) => { // Triggers when search bar is changed
  // remove error bubble
  setAlertMessage(new AlertData('', false));
  const nameValue = e.target.value; // get the new input
  setName(nameValue); // set the new input
  // even if we've selected already an item from the list, we should reset it since it's been changed
  setIsNameSelected(false);
  setResults([]); // clean previous results
  if (nameValue.length > 1) { // if the input is more than 1 character
    setIsLoading(true); // set loading to true
    updateSearchInput(nameValue)  // get the results
      .then((res) => {
        setResults(res as React.SetStateAction<never[]>); // set the results
        setIsLoading(false); // set loading to false
      })
      .catch((error) => {
        // error bubble
        let strError = error.message;
        strError = strError.split(':').pop();
        let errorMessage: AlertData = new AlertData(strError, true); // create error message for empty search
        setAlertMessage(errorMessage); // set alert message
        // loading spinner
        setIsLoading(false);
      });
  }
}

However when there is an input change in form control, like typing in an entire word, the search functionality works, populating the DOM with suggested words. However when I clear the value in FormControl really fast (by pressing Backspace/Delete several times in quick succession), then the search results stay. Doing it slow or selecting and clearing it all at once however does not show this erratic behavior.

I have used console.log to print out the value of results in the an empty component like this:

{console.log(results) && (<div><div/>)}

in return statement of App to see what the contents of results are. However it does show that results value were not updated by setResults().

This problem however does not exist for the other states utilized here. Why?

EDIT

From the answer accepted below from @ghybs. This is a timeline of what might be happening with the call:

  1. Enter search
  2. await call runs but request response is slow so takes a while.
  3. Delete all the keyword in search
  4. results is made empty with setResults([]) in handleInputChange call.
  5. await call finishes. setResults(res as React.SetStateAction<never[]>) runs making results non-empty.

CodePudding user response:

You very probably just have plenty concurrent requests (1 per key stroke, including back space?), and unordered results from your updateSearchInput async function: the last received one overwrites your results, but that one may not originate from your last key stroke (the one that removed the last character from your textarea).

Typically if an empty search is faster than a search with plenty words, the results from empty input do clear your results, but then these are filled again by the results of a previous search.

  • Related