0

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}])
      }
}

1 Answer 1

1

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/

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

2 Comments

I edited the question with this: cities is already a state with all the cities and states in the US. And thisCity and thisState is also already declared.
Yeah, but it's declared outside your for loop. It needs to be declared inside your loop. Otherwise when the callback is called, it'll only see the most recent value set to it.

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.