Je suis juste en train d'écrire en saisie de texte et dans onChange
, j'appelle setState
, donc React redirige mon interface utilisateur. Le problème est que la saisie de texte perd toujours un focus, je dois donc le focaliser à nouveau pour chaque lettre: 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>
);
}
});
Sans voir le reste de votre code, il s'agit d'une estimation ..___. Lorsque vous créez un EditorContainer, spécifiez une clé unique pour le composant:
<EditorContainer key="editor1"/>
Lorsqu'un re-rendu se produit, si la même clé est vue, cela indique à React de ne pas obstruer et de régénérer la vue, mais de le réutiliser. Ensuite, l'élément ciblé doit rester actif.
S'il s'agit d'un problème dans un routeur de réaction, <Route/>
, utilisez la propriété render
au lieu de component
.
<Route path="/user" render={() => <UserPage/>} />
La perte de concentration se produit parce que la propriété component
utilise React.createElement
à chaque fois au lieu de simplement restituer les modifications.
Détails ici: https://reacttraining.com/react-router/web/api/Route/component
Je reviens encore et encore et je trouve toujours la solution à mon problème ailleurs à la fin… Donc, je vais la documenter ici parce que je sais que je l'oublierai encore!
La raison pour laquelle input
perdait de son attention dans mon cas était due au fait que je rendais de nouveau le input
sur le changement d'état.
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>
)
}
}
Donc, le problème est que je commence toujours à tout coder à un endroit pour le tester rapidement, puis le diviser en modules distincts . .
La correction est simple, faites la modularisation depuis le début, autrement dit, "déplacez le composant Input
de la fonction render
"
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>
)
}
}
Réf. à la solution: https://github.com/styled-components/styled-components/issues/540#issuecomment-283664947
Ma réponse est similaire à celle de @ z5h.
Dans mon cas, j'ai utilisé Math.random()
pour générer un key
unique pour le composant.
Je pensais que la variable key
n'était utilisée que pour déclencher une restitution pour ce composant particulier plutôt que de restituer tous les composants de ce tableau (je retourne un tableau de composants dans mon code). Je ne savais pas qu'il est utilisé pour restaurer l'état après la restitution.
Enlever ça a fait le travail pour moi.
PS: J'aurais pu commenter cela, mais je n'ai pas assez de réputation pour ça.
J'ai le même comportement.
Le problème dans mon code est que j'ai créé un tableau imbriqué d'éléments jsx comme ceci:
const example = [
[
<input value={'Test 1'}/>,
<div>Test 2</div>,
<div>Test 3</div>,
]
]
...
render = () => {
return <div>{ example }</div>
}
Chaque élément de ce tableau imbriqué est rendu à chaque fois que j'ai mis à jour l'élément parent. Et donc les entrées perdent là "ref" prop à chaque fois
J'ai corrigé le problème avec la transformation du tableau interne en un composant de réaction (Une fonction avec une fonction de rendu)
const example = [
<myComponentArray />
]
...
render = () => {
return <div>{ example }</div>
}
MODIFIER:
Le même problème apparaît lorsque je crée un React.Fragment
imbriqué
const SomeComponent = (props) => (
<React.Fragment>
<label ... />
<input ... />
</React.Fragment>
);
const ParentComponent = (props) => (
<React.Fragment>
<SomeComponent ... />
<div />
</React.Fragment>
);
Je viens de rencontrer ce problème et je suis venu ici pour obtenir de l'aide. Vérifiez votre CSS! Le champ de saisie ne peut pas avoir user-select: none;
ou ne fonctionnera pas sur un iPad.
L'application de l'attribut autoFocus
à l'élément input
peut constituer une solution de contournement dans les cas où une seule entrée doit être ciblée. Dans ce cas, un attribut key
serait inutile car il ne s'agit que d'un élément. De plus, vous n'aurez pas à craindre de diviser l'élément input
en son propre composant pour éviter de perdre le focus sur le rendu du composant principal.
La raison principale est la suivante: lorsque React restitue, votre précédente référence DOM sera invalide. Cela signifie que réagit a changé l’arborescence DOM et que ceci.refs.input.focus ne fonctionnera pas, car l’entrée n’existe plus.
Pour moi, cela était dû au fait que la zone de saisie de la recherche était rendue dans le composant même (appelé UserList) en tant que liste des résultats de la recherche. Ainsi, chaque fois que les résultats de la recherche sont modifiés, l'ensemble du composant UserList est renvoyé, y compris la zone de saisie.
Ma solution consistait à créer un tout nouveau composant appelé UserListSearch qui est séparé de UserList . Je n'avais pas besoin de définir des clés sur les champs de saisie dans UserListSearch pour que cela fonctionne. La fonction de rendu de mon UsersContainer ressemble maintenant à ceci:
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>
)
}
}
Espérons que cela aide aussi quelqu'un.
Les réponses fournies ne m'ont pas aidé, voici ce que j'ai fait mais j'avais une situation unique.
Pour nettoyer le code, j'ai tendance à utiliser ce format jusqu'à ce que je sois prêt à extraire le composant dans un autre fichier.
render(){
const MyInput = () => {
return <input onChange={(e)=>this.setState({text: e.target.value}) />
}
return(
<div>
<MyInput />
</div>
)
Mais cela l'a fait perdre le focus, lorsque j'ai mis le code directement dans le div cela a fonctionné.
return(
<div>
<input onChange={(e)=>this.setState({text: e.target.value}) />
</div>
)
Je ne sais pas pourquoi, c’est le seul problème que j’ai eu à l’écrire de cette façon et je le fais dans la plupart des fichiers que j’ai, mais si quelqu'un fait la même chose, c’est la raison pour laquelle il perd le focus.
J'ai eu le même problème avec une table HTML dans laquelle j'ai des lignes de texte dans une colonne. Dans une boucle, je lis un objet JSON et je crée des lignes, en particulier, j'ai une colonne avec inputtext.
http://reactkungfu.com/2015/09/react-js-loses-input-focus-on-typing/
J'ai réussi à le résoudre de la manière suivante
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>
);
}
}
Mon problème était que j'ai nommé ma clé dynamiquement avec une valeur de l'item, dans mon cas "nom" donc la clé était key = {${item.name}-${index}
}. Donc, lorsque je voulais changer l'entrée avec item.name comme valeur, la clé était également modifiée et donc, la réaction ne reconnaissait pas cet élément
Il s'avère que je liais this
au composant qui le rendait.
Je pensais le poster ici au cas où quelqu'un d'autre aurait ce problème.
Je devais changer
<Field
label="Post Content"
name="text"
component={this.renderField.bind(this)}
/>
À
<Field
label="Post Content"
name="text"
component={this.renderField}
/>
Solution simple car dans mon cas, je n'avais pas besoin de this
dans renderField
, mais j'espère que le fait de poster ceci aidera quelqu'un d'autre.
J'ai changé value
prop en defaultValue
. Ça marche pour moi.
...
// before
<input value={myVar} />
// after
<input defaultValue={myVar} />