This happens because the useState hook is not "hooked" to your SearchComponent, but your MyInput component. Whenever, you call updateCitySearch() you change the state of MyInput, thus forcing the entire component to re-render.
SearchComponent, is explicitly defined inside MyInput. When citySearch-state is updated, SearchComponent loses focus because the initial virual DOM surrounding it is no longer intact, instead you have a completely new piece of DOM. Essentially, you are creating a brand new SearchComponent each time the MyInput is updated by state.
Consider the following example:
function App() {
const [citySearch, updateCitySearch] = useState("");
console.log("rendered App again"); //always prints
const SearchComponent = () => {
console.log("rendered Search"); //always prints
const searchCityClick = () => {
alert(citySearch);
};
return (
<div>
<input
value={citySearch}
onChange={e => {
updateCitySearch(e.target.value);
}}
/>
<button onClick={searchCityClick}>Search</button>
</div>
);
};
return (
<div>
<div>
<SearchComponent />
</div>
</div>
);
}
Every time you update state, you would trigger both console.log(), the App component re-renders and SearchComponent gets re-created. A new iteration of myInput is rendered each time and a new SearchComponent gets created.
But if you were to define useState inside SearchComponent, then only SearchComponent will re-render whens state changes, thus leaving the original myInput component unchanged, and the current SearchComponent intact.
function App() {
console.log("rendered App again"); //would never print a 2nd time.
const SearchComponent = () => {
const [citySearch, updateCitySearch] = useState("");
console.log("rendered Search"); //would print with new state change
const searchCityClick = () => {
alert(citySearch);
};
return (
<div>
<input
value={citySearch}
onChange={e => {
updateCitySearch(e.target.value);
}}
/>
<button onClick={searchCityClick}>Search</button>
</div>
);
};
return (
<div>
<div>
<SearchComponent />
</div>
</div>
);
}