简体   繁体   中英

React JS updating setState in a for loop

I want to be able to add array values to a setState in React JS. Basically I'm doing a search bar for cities. Every time the user types, it will update the setState to include a more filtered search. Basically, if the user wants to search for 'Los Angeles, California', they'll type in 'L' first. So then the program searches for all the cities that start with 'L' and add them to the setState . Then the user proceeds 'Lo', then the program searches for all the cities that start with 'Lo' and updates the setState with only cities that start with 'Lo' and so on and so forth.

For some reason, it always repeats the same city 100 times. So if the person types in 'L' it adds the first city 100 times to setState instead of the first 100 different cities. Below is my code. I'm using it in a for loop.

cities is already a state with every city and state in the US. thisCity and thisState is already declared.

for (var i = 0; i < cities.length; i++){
      if(cities[i].city.toUpperCase().startsWith(e.target.value.toUpperCase())){
        thisCity = cities[i].city;
        thisState = cities[i].state;

        setSuggest((suggest) => [...suggest, {id: Math.random() * 1000,
        city: thisCity,
        state: thisState}])
      }
}

There are a few issues here.

First, replace var i = 0 with let i = 0 . var scopes globally, where as let scopes to the block.

Secondly, you have not declared the variables thisCity and thisState , so they are also being set globally. Declare them using const , since they won't be changing.

Whenever your callback function inside setSuggest is called, it's getting the very last value set to thisCity and thisState, instead of the value scoped to that block. This is because the callback function is executed later. If you put a console.log inside setSuggest, and another one at the end of your for loop, you'd see the log for the for loop occur before the one for the setSuggest.

Lastly, you should figure out the list of cities first, and then set your state. This will be significantly more performant. Overall, I'd recommend replacing your for-loop in favor of using the array method .filter :

const compareTo = e.target.value.toUpperCase();
const suggestions = cities.filter(city => (
  city.toUpperCase().startsWith(compareTo)
));
setSuggest(suggestions);

I found this article that may help you understand variable scope a little better: https://dmitripavlutin.com/javascript-scope-gotchas/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM