React.js - input focus for reengineering

I am just writing to enter text and in the onChange event I call setState , so React changes my user interface. The problem is that text input always loses focus, so I need to configure it again for each letter: D.

 var EditorContainer = React.createClass({ componentDidMount: function () { $(this.getDOMNode()).slimScroll({height: this.props.height, distance: '4px', size: '8px'}); }, componentDidUpdate: function () { console.log("zde"); $(this.getDOMNode()).slimScroll({destroy: true}).slimScroll({height: 'auto', distance: '4px', size: '8px'}); }, changeSelectedComponentName: function (e) { //this.props.editor.selectedComponent.name = $(e.target).val(); this.props.editor.forceUpdate(); }, render: function () { var style = { height: this.props.height + 'px' }; return ( <div className="container" style={style}> <div className="row"> <div className="col-xs-6"> {this.props.selected ? <h3>{this.props.selected.name}</h3> : ''} {this.props.selected ? <input type="text" value={this.props.selected.name} onChange={this.changeSelectedComponentName} /> : ''} </div> <div className="col-xs-6"> <ComponentTree editor={this.props.editor} components={this.props.components}/> </div> </div> </div> ); } }); 
+70
javascript reactjs
source share
14 answers

Without seeing the rest of the code, this is an assumption. When you create the EditorContainer, specify a unique key for the component:

<EditorContainer key="editor1"/>

When re-rendering, if the same key is noticed, it will say that React will not hide and will not restore the view, but reuse. Then the focused element should maintain focus.

+66
source share

If this is a problem in the <Route/> reply router, use render prop instead of component .

 <Route path="/user" render={() => <UserPage/>} /> 


Loss of focus happens because component prop uses React.createElement every time instead of just redrawing the changes.

Details here: https://reacttraining.com/react-router/web/api/Route/component

+26
source share

I come back here again and again and always find a solution for my other place at the end. So, I will document it here because I know that I will forget it again!

The reason that input lost focus in my case was because I re-displayed input when the state changed.

Error code:

 import React from 'react'; import styled from 'styled-components'; class SuperAwesomeComp extends React.Component { state = { email: '' }; updateEmail = e => { e.preventDefault(); this.setState({ email: e.target.value }); }; render() { const Container = styled.div''; const Input = styled.input''; return ( <Container> <Input type="text" placeholder="Gimme your email!" onChange={this.updateEmail} value={this.state.email} /> </Container> ) } } 

So, the problem is that I always start to code everything in one place in order to quickly test, and then break everything into separate modules. But here this strategy has unpleasant consequences, because updating the state when changing the input starts the rendering function, and the focus is lost.

Itโ€™s easy to fix, to modularize from the very beginning, in other words: โ€œMove the Input component from the render functionโ€.

Fixed code

 import React from 'react'; import styled from 'styled-components'; const Container = styled.div''; const Input = styled.input''; class SuperAwesomeComp extends React.Component { state = { email: '' }; updateEmail = e => { e.preventDefault(); this.setState({ email: e.target.value }); }; render() { return ( <Container> <Input type="text" placeholder="Gimme your email!" onChange={this.updateEmail} value={this.state.email} /> </Container> ) } } 

Link to the solution: https://github.com/styled-components/styled-components/issues/540#issuecomment-283664947

+23
source share

My answer is similar to what @ z5h said.

In my case, I used Math.random() to generate a unique key for the component.

I thought that key is only used to start rendering for this particular component, and not to render all the components in this array (I am returning an array of components in my code). I did not know that it is used to restore state after redrawing.

Removing this did the job for me.

PS: I could comment on this, but I do not have enough reputation for this.

+6
source share

I just ran into this problem and came here for help. Test your CSS! The input field cannot have user-select: none; or it will not work on the iPad.

+3
source share

I have the same behavior.

The problem in my code was that I created a nested array of jsx elements, for example:

 const example = [ [ <input value={'Test 1'}/>, <div>Test 2</div>, <div>Test 3</div>, ] ] ... render = () => { return <div>{ example }</div> } 

Each element of this nested array is redrawn every time I update the parent element. And so the inputs lose their "ref" support there every time

I fixed the problem with converting the internal array into a responsive component (function with rendering function)

 const example = [ <myComponentArray /> ] ... render = () => { return <div>{ example }</div> } 

EDIT:

The same problem occurs when I create a nested React.Fragment

 const SomeComponent = (props) => ( <React.Fragment> <label ... /> <input ... /> </React.Fragment> ); const ParentComponent = (props) => ( <React.Fragment> <SomeComponent ... /> <div /> </React.Fragment> ); 
+3
source share

Applying the autoFocus attribute to an input element can be a workaround in situations where only one input is needed that needs to be focused. In this case, the key attribute would be superfluous, because it is just one element, and you no longer have to worry about breaking the input element into your own component, to avoid losing attention when you re-render the main component.

+2
source share

The main reason is this: when you re-render React, your previous DOM code will be invalid. This means that the reaction changed the DOM tree and you this.refs.input.focus will not work, because the input no longer exists here.

+1
source share

The answers didn't help me, that's what I did, but I had a unique situation.

To clear the code, I try to use this format until I am ready to pull the component into another file.

 render(){ const MyInput = () => { return <input onChange={(e)=>this.setState({text: e.target.value}) /> } return( <div> <MyInput /> </div> ) 

But that made him lose focus when I put the code directly in the div he worked with.

 return( <div> <input onChange={(e)=>this.setState({text: e.target.value}) /> </div> ) 

I donโ€™t know why this is so, this is the only problem I encountered writing it this way, and I do it in most of the files that I have, but if someone does this, then why does he lose focus.

+1
source share

I had the same issue with an HTML table in which I have text input lines in a column. inside the loop, I read the json object and create the rows, in particular, I have a column with inputtext.

http://reactkungfu.com/2015/09/react-js-loses-input-focus-on-typing/

I managed to solve it as follows

 import { InputTextComponent } from './InputTextComponent'; //import my inputTextComponent ... var trElementList = (function (list, tableComponent) { var trList = [], trElement = undefined, trElementCreator = trElementCreator, employeeElement = undefined; // iterating through employee list and // creating row for each employee for (var x = 0; x < list.length; x++) { employeeElement = list[x]; var trNomeImpatto = React.createElement('tr', null, <td rowSpan="4"><strong>{employeeElement['NomeTipologiaImpatto'].toUpperCase()}</strong></td>); trList.push(trNomeImpatto); trList.push(trElementCreator(employeeElement, 0, x)); trList.push(trElementCreator(employeeElement, 1, x)); trList.push(trElementCreator(employeeElement, 2, x)); } // end of for return trList; // returns row list function trElementCreator(obj, field, index) { var tdList = [], tdElement = undefined; //my input text var inputTextarea = <InputTextComponent idImpatto={obj['TipologiaImpattoId']}//index value={obj[columns[field].nota]}//initial value of the input I read from my json data source noteType={columns[field].nota} impattiComposite={tableComponent.state.impattiComposite} //updateImpactCompositeNote={tableComponent.updateImpactCompositeNote} /> tdElement = React.createElement('td', { style: null }, inputTextarea); tdList.push(tdElement); var trComponent = createClass({ render: function () { return React.createElement('tr', null, tdList); } }); return React.createElement(trComponent); } // end of trElementCreator }); ... //my tableComponent var tableComponent = createClass({ // initial component states will be here // initialize values getInitialState: function () { return { impattiComposite: [], serviceId: window.sessionStorage.getItem('serviceId'), serviceName: window.sessionStorage.getItem('serviceName'), form_data: [], successCreation: null, }; }, //read a json data soure of the web api url componentDidMount: function () { this.serverRequest = $.ajax({ url: Url, type: 'GET', contentType: 'application/json', data: JSON.stringify({ id: this.state.serviceId }), cache: false, success: function (response) { this.setState({ impattiComposite: response.data }); }.bind(this), error: function (xhr, resp, text) { // show error to console console.error('Error', xhr, resp, text) alert(xhr, resp, text); } }); }, render: function () { ... React.createElement('table', {style:null}, React.createElement('tbody', null,trElementList(this.state.impattiComposite, this),)) ... } //my input text var inputTextarea = <InputTextComponent idImpatto={obj['TipologiaImpattoId']}//index value={obj[columns[field].nota]}//initial value of the input I read //from my json data source noteType={columns[field].nota} impattiComposite={tableComponent.state.impattiComposite}//impattiComposite = my json data source />//end my input text tdElement = React.createElement('td', { style: null }, inputTextarea); tdList.push(tdElement);//add a component //./InputTextComponent.js import React from 'react'; export class InputTextComponent extends React.Component { constructor(props) { super(props); this.state = { idImpatto: props.idImpatto, value: props.value, noteType: props.noteType, _impattiComposite: props.impattiComposite, }; this.updateNote = this.updateNote.bind(this); } //Update a inpute text with new value insert of the user updateNote(event) { this.setState({ value: event.target.value });//update a state of the local componet inputText var impattiComposite = this.state._impattiComposite; var index = this.state.idImpatto - 1; var impatto = impattiComposite[index]; impatto[this.state.noteType] = event.target.value; this.setState({ _impattiComposite: impattiComposite });//update of the state of the father component (tableComponet) } render() { return ( <input className="Form-input" type='text' value={this.state.value} onChange={this.updateNote}> </input> ); } } 
+1
source share

For me, this was due to the fact that the search input field was displayed in the same component (called UserList) as the list of search results. Thus, whenever the search results changed, the entire UserList component was redrawn, including the input field.

My solution was to create a completely new component called UserListSearch, which is separate from UserList . I did not need to set the keys in the input fields in UserListSearch for this to work. The rendering function of my UsersContainer now looks like this:

 class UserContainer extends React.Component { render() { return ( <div> <Route exact path={this.props.match.url} render={() => ( <div> <UserListSearch handleSearchChange={this.handleSearchChange} searchTerm={this.state.searchTerm} /> <UserList isLoading={this.state.isLoading} users={this.props.users} user={this.state.user} handleNewUserClick={this.handleNewUserClick} /> </div> )} /> </div> ) } } 

Hope this helps someone too.

+1
source share

Turns out I linked this to a component that caused it to be re-rendered.

I decided to post this here in case anyone else has this problem.

I had to change

 <Field label="Post Content" name="text" component={this.renderField.bind(this)} /> 

to

 <Field label="Post Content" name="text" component={this.renderField} /> 

A simple fix, as in my case I did not need this renderField in renderField , but hopefully my post will help someone else.

0
source share

I switched value prop to defaultValue . This is suitable for me.

 ... // before <input value={myVar} /> // after <input defaultValue={myVar} /> 
0
source share

My problem was that I named my key dynamically with the value of the element, in my case "name", so the key was key = { ${item.name}-${index} }. Therefore, when I wanted to change the input using item.name as the value, they also changed the key and, therefore, reacted, did not recognize this element.

0
source share

All Articles