77435

Input is loosing focus on hooks update

<h3>Question</h3>

I'm new to reactjs and I'm trying read data from input. Problem is when I type a sign, my input loose focus. But only when all logic is inside function. When Input with button and logic is in different file - it's working. I don't really know why...

I have created separate file with same code and import it to sollution - it's ok. I have tried with onChange={handleChange} - lost focus as well.

export default function MyInput(){ const [citySearch, updateCitySearch] = useState(); function searchCityClick(){ alert(citySearch); } const SearchComponent = ()=> ( <div> <input value={citySearch} onChange={(e) => updateCitySearch(e.target.value)}/> <Button variant="contained" color="primary" onClick={searchCityClick}> Search </Button> </div> ); return( <div> <div> <SearchComponent /> </div> </div> )}
<h3>Answer1:</h3>

The SearchComponent is a functional component, and shouldn't be defined inside another component. Defining SearchComponent inside MyInput will cause SearchComponent to be recreated (not rerendered), and in essence it's DOM would be removed, and then added back on every click.

The solution is pretty straightforward, extract SearchComponent from MyInput, and pass the functions, and the data via the props object:

<pre class="snippet-code-js lang-js prettyprint-override">const { useState, useCallback } = React; const SearchComponent = ({ citySearch, updateCitySearch, searchCityClick }) => ( <div> <input value={citySearch} onChange={e => updateCitySearch(e.target.value)} /> <button onClick={searchCityClick}>Search</button> </div> ); const MyInput = () => { const [citySearch, updateCitySearch] = useState(''); const searchCityClick = () => alert(citySearch); return( <div> <SearchComponent citySearch={citySearch} updateCitySearch={updateCitySearch} searchCityClick={searchCityClick} /> </div> ); }; ReactDOM.render( <MyInput />, root ); <pre class="snippet-code-html lang-html prettyprint-override"><script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div id="root"></div>
<h3>Answer2:</h3>

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> ); }
<h3>Answer3:</h3>

I am also new to React, so take my explanation with a pinch of salt (hopefully someone else can elaborate).. I believe it has something to do with nesting components and how React is re-rendering..

If you use SearchComponent as a variable, instead of an anonymous function, this works as expected.

I am also curious as to why using nested functions like that (when using JSX) causes this behavior... possibly an anti-pattern?

<pre class="snippet-code-js lang-js prettyprint-override">function MyInput() { const [citySearch, updateCitySearch] = React.useState(); function searchCityClick() { alert(citySearch); } const SearchComponent = ( <div> <input value={citySearch} onChange={(e) => updateCitySearch(e.target.value)}/> <button variant="contained" color="primary" onClick={searchCityClick}> Search </button> </div> ); return ( <div> <div> {SearchComponent} </div> </div> ); } let div = document.createElement("div"); div.setAttribute("id", "app"); document.body.append(div); ReactDOM.render(<MyInput />, document.getElementById("app")); <pre class="snippet-code-html lang-html prettyprint-override"><script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>

Even if you change the nested function to an "actual component", focus is lost after each key press (aka onChange)..

Does not work:

function MyInput() { const [citySearch, updateCitySearch] = React.useState(); function searchCityClick() { alert(citySearch); } const SearchComponent = () => { return ( <div> <input value={citySearch} onChange={(e) => updateCitySearch(e.target.value)}/> <button variant="contained" color="primary" onClick={searchCityClick}> Search </button> </div> ); } return ( <div> <div> <SearchComponent /> </div> </div> ); }

来源:https://stackoverflow.com/questions/56758864/input-is-loosing-focus-on-hooks-update

Recommend

  • JQuery FullCalendar trouble with invoking rerenderEvents from ajax success
  • Simple PHP mongoDB Username and Password Check for site
  • HTML input field height different in different browsers
  • The underlying provider failed on Open after deleting database files and sqllocaldb
  • Group by user and show latest in MYSQL not working
  • Can not open created raster in R
  • displaying data from multiple tables in datagridview
  • Ping a Bluetooth device from an Android device
  • xcode 9.0.1 / swift 4, No method declared with Objective-C selector 'onClick:forEvent:' [d
  • Adding items to an already existing jlist from another class
  • Xamarin.Forms bind Height of Grid to Width of Button
  • Selenium - how to switch to a different (login) window that is brought up?
  • JSF validateLength question
  • Whatsapp Image sharing not working
  • Silverlight MVVM, stop SelectionChanged triggering in response to ItemsSource reset
  • How to print every 4th column up to nth column and from (n+1)th column to last using awk?
  • Shopify Custom Payment Gateway Implementation
  • How to manipulate content of a comment with Apache POI
  • Vue.js 2: Vue cannot find files from /assets folder (v-for)
  • How to implement JQuery confirm dialog with JSF
  • Run git bash script in Windows 7/64bit
  • python socket.sendto
  • Tensorflow crash using tf.train.Saver() with GPU
  • How to get the Owner of the ContextMenu (from Silverlight 4 toolkit)?
  • Facebook friend list in Facebook Android SDK 3.14
  • Unable to run testNG tests from maven
  • JQuery Mobile Ajax Navigation in Single-Page Template
  • How to add html image in to velocity template file to send email?
  • Does hibernate load two seprate copies of same instance if they are loaded twice from database?
  • Excel File upload in asp.net using SqlBulkCopy
  • how to specify different css for ie
  • How to merge objects within array based on attribute
  • concise way of flattening multiindex columns
  • VS2010 RDLC C#. How can I set a LocalReport object to a ReportViewer?
  • Drag and drop unicode TText in DelphiXe4
  • jQuery scrollTop if URL has hash
  • Using redis as an LRU cache for postgres
  • read part of h5 dataset python
  • convert json to excel in java