Quel est le moyen de réactiver le focus sur un champ de texte particulier après le rendu du composant?
La documentation semble suggérer l’utilisation de références, par exemple:
Définissez ref="nameInput"
sur mon champ de saisie dans la fonction de rendu, puis appelez:
this.refs.nameInput.getInputDOMNode().focus();
Mais où devrais-je appeler cela? J'ai essayé quelques endroits mais je n'arrive pas à le faire fonctionner.
Vous devriez le faire dans componentDidMount
et refs callback
. Quelque chose comme ça
_componentDidMount(){
this.nameInput.focus();
}
_
_class App extends React.Component{
componentDidMount(){
this.nameInput.focus();
}
render() {
return(
<div>
<input
defaultValue="Won't focus"
/>
<input
ref={(input) => { this.nameInput = input; }}
defaultValue="will focus"
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
_
_<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js"></script>
<div id="app"></div>
_
La réponse de @ Dhiraj est correcte et, pour plus de commodité, vous pouvez utiliser l'autofocus pour qu'une entrée soit automatiquement mise au point lorsqu'elle est montée:
<input autoFocus name=...
Notez que dans jsx, il s’agit de autoFocus
(F majuscule), contrairement à HTML classique qui n’est pas sensible à la casse.
À partir de React 0.15, la méthode la plus concise est la suivante:
<input ref={input => input && input.focus()}/>
Si vous voulez juste faire l'autofocus dans React, c'est simple.
<input autoFocus type="text" />
Tandis que si vous voulez juste savoir où mettre ce code, answer est dans composantDidMount ().
v014.3
componentDidMount() {
this.refs.linkInput.focus()
}
Dans la plupart des cas, vous pouvez attacher une référence au nœud DOM et éviter d'utiliser findDOMNode.
Lisez les documents de l'API ici: https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode
Si vous voulez simplement focaliser un élément quand il monte (rend initialement), une simple utilisation de l'attribut autoFocus fera l'affaire.
<input type="text" autoFocus />
pour contrôler la mise au point de manière conditionnelle, utilisez la composition de fonction pour masquer les détails de mise en œuvre de dom et de navigateur de vos composants.
const useFocus = () => {
const htmlElRef = useRef(null)
const setFocus = () => {htmlElRef.current && htmlElRef.current.focus()}
return [ setFocus, htmlElRef ]
}
Ensuite, utilisez-le dans n'importe quel composant fonctionnel.
const FocusDemo = () => {
const [value, setValue] = useState("")
const [setInputFocus, inputRef] = useFocus()
const [setBtnFocus, btnRef] = useFocus()
return (
<> {/* React.Fragment */}
<input
value={value}
onChange={(e)=>{
setValue(e.target.value)
if ( some logic ){ setBtnFocus() }
}}
ref={inputRef}
/>
<button
onClick={setInputFocus}
ref={btnRef}
>
Refocus
</button>
</>
)
}
const utilizeFocus = () => {
const ref = React.createRef()
const setFocus = () => {ref.current && ref.current.focus()}
return {setFocus, ref}
}
Puis utilisez-le dans n'importe quel composant de classe
class App extends Component {
constructor(props){
super(props)
this.input1Focus = utilizeFocus()
this.BtnFocus = utilizeFocus()
}
render(){
return (
<> {/* React.Fragment */}
<input
value={value}
onChange={(e)=>{
setValue(e.target.value)
if ( some logic ){ this.BtnFocus.setFocus() }
}}
ref={this.input1Focus.ref}
/>
<button
onClick={this.input1Focus.setFocus()}
ref={this.BtnFocus.ref}
>
Refocus
</button>
</>
)
}
}
Je viens de rencontrer ce problème et je me sers de réagir 15.0.1 15.0.2 et j’utilise la syntaxe ES6 et n’ai pas tout à fait obtenu ce dont j’avais besoin des autres réponses depuis que v.15 a été abandonné il ya plusieurs semaines et que certaines des propriétés this.refs
sont obsolètes et supprimé .
En général, ce dont j'avais besoin était:
J'utilise:
J'ai utilisé autoFocus={true}
sur le premier <input />
de la page afin que, lorsque le composant est monté, il obtienne le focus.
Cela a pris plus de temps et a été plus compliqué. Je garde le code qui n'est pas pertinent pour la solution par souci de concision.
J'ai besoin d'un état global pour savoir si je dois définir le focus et le désactiver quand il a été défini, pour ne pas continuer à le redéfinir lorsque les composants sont restitués (je vais utiliser componentDidUpdate()
pour vérifier la mise au point.)
Cela pourrait être conçu comme bon vous semble pour votre application.
{
form: {
resetFocus: false,
}
}
Le composant doit avoir la propriété resetfocus
définie et un callback pour effacer la propriété s'il finit par définir le focus sur lui-même.
Notez également que j'ai organisé mes créateurs d'action dans des fichiers séparés, principalement en raison de la taille relativement importante de mon projet et que je souhaitais les scinder en plusieurs morceaux plus faciles à gérer.
import { connect } from 'react-redux';
import MyField from '../presentation/MyField';
import ActionCreator from '../actions/action-creators';
function mapStateToProps(state) {
return {
resetFocus: state.form.resetFocus
}
}
function mapDispatchToProps(dispatch) {
return {
clearResetFocus() {
dispatch(ActionCreator.clearResetFocus());
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MyField);
import React, { PropTypes } form 'react';
export default class MyField extends React.Component {
// don't forget to .bind(this)
constructor(props) {
super(props);
this._handleRef = this._handleRef.bind(this);
}
// This is not called on the initial render so
// this._input will be set before this get called
componentDidUpdate() {
if(!this.props.resetFocus) {
return false;
}
if(this.shouldfocus()) {
this._input.focus();
this.props.clearResetFocus();
}
}
// When the component mounts, it will save a
// reference to itself as _input, which we'll
// be able to call in subsequent componentDidUpdate()
// calls if we need to set focus.
_handleRef(c) {
this._input = c;
}
// Whatever logic you need to determine if this
// component should get focus
shouldFocus() {
// ...
}
// pass the _handleRef callback so we can access
// a reference of this element in other component methods
render() {
return (
<input ref={this._handleRef} type="text" />
);
}
}
Myfield.propTypes = {
clearResetFocus: PropTypes.func,
resetFocus: PropTypes.bool
}
L'idée générale est que chaque champ de formulaire susceptible d'avoir une erreur et d'être ciblé doit se vérifier et s'il doit se focaliser sur lui-même.
Il faut qu'il y ait une logique métier pour déterminer si le champ donné est le bon champ sur lequel se concentrer. Cela ne s'affiche pas car cela dépend de l'application individuelle.
Lorsqu'un formulaire est soumis, cet événement doit définir l'indicateur de focus global resetFocus
sur true. Ensuite, chaque composant se mettant à jour, il verra qu'il doit vérifier s'il obtient le focus et, le cas échéant, envoie l'événement pour le réinitialiser afin que les autres éléments n'aient pas à vérifier.
edit En remarque, j'avais ma logique métier dans un fichier "utilitaires" et je venais d'exporter la méthode et de l'appeler dans chaque shouldfocus()
méthode.
À votre santé!
Les documents React _ ont maintenant une section pour cela. https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute
render: function() {
return (
<TextInput
ref={function(input) {
if (input != null) {
input.focus();
}
}} />
);
},
React 16.3 a ajouté un nouveau moyen pratique de gérer cela en créant une référence dans le constructeur du composant et en l'utilisant comme ci-dessous:
class MyForm extends Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
componentDidMount() {
this.textInput.current.focus(); // one important change here is that we need to access the element via current.
}
render() {
// instead of using arrow function, the created ref can be used directly.
return(
<div>
<input ref={this.textInput} />
</div>
);
}
}
Pour plus de détails, vous pouvez vérifier cet article dans React blog.
Mise à jour:
À partir de React 16.8 , useRef
hook peut être utilisé dans les composants de la fonction pour obtenir le même résultat:
import React, { useEffect, useRef } from 'react';
const MyForm = () => {
const textInput = useRef(null);
useEffect(() => {
textInput.current.focus();
}, []);
return (
<div>
<input ref={textInput} />
</div>
);
};
C’est la bonne façon de faire la mise au point automatique. Lorsque vous utilisez callback au lieu de chaîne comme valeur de référence, celle-ci est automatiquement appelée. Vous avez votre référence disponible que sans avoir besoin de toucher le DOM avec getDOMNode
render: function() {
return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
this._input.focus();
},
Réf. Commentaire de @ Dave sur la réponse de @ Dhiraj; une alternative consiste à utiliser la fonctionnalité de rappel de l'attribut ref sur l'élément en cours de rendu (après le premier rendu du composant):
<input ref={ function(component){ React.findDOMNode(component).focus();} } />
Ce n'est plus la meilleure réponse. À partir de la v0.13, il est possible que this.refs
ne soit pas disponible avant l'exécution de AFTER componentDidMount()
, dans certains cas étranges.
Ajoutez simplement la balise autoFocus
à votre champ de saisie, comme le montre FakeRainBrigand ci-dessus.
Vous pouvez mettre cet appel de méthode dans la fonction de rendu. Ou dans la méthode du cycle de vie, componentDidUpdate
Notez qu'aucune de ces réponses n'a fonctionné pour moi avec un composant TextField matériel-ui . Per Comment définir le focus sur un materialUI TextField? Je devais sauter à travers quelques cerceaux pour que cela fonctionne:
const focusUsernameInputField = input => {
if (input) {
setTimeout(() => {input.focus()}, 100);
}
};
return (
<TextField
hintText="Username"
floatingLabelText="Username"
ref={focusUsernameInputField}
/>
);
Vous n'avez pas besoin de getInputDOMNode
?? dans ce cas...
Obtenez simplement les ref
et focus()
quand le composant est monté - composantDidMount ...
import React from 'react';
import { render } from 'react-dom';
class myApp extends React.Component {
componentDidMount() {
this.nameInput.focus();
}
render() {
return(
<div>
<input ref={input => { this.nameInput = input; }} />
</div>
);
}
}
ReactDOM.render(<myApp />, document.getElementById('root'));
AutoFocus a fonctionné mieux pour moi. J'avais besoin de changer du texte en une entrée avec ce texte en double-clic donc c'est ce que j'ai fini avec:
<input autoFocus onFocus={this.setCaretToEnd} value={this.state.editTodo.value} onDoubleClick={this.updateTodoItem} />
REMARQUE: pour résoudre le problème où React place le signe d'insertion au début du texte, utilisez cette méthode:
setCaretToEnd(event) {
var originalText = event.target.value;
event.target.value = '';
event.target.value = originalText;
}
Trouvé ici: https://coderwall.com/p/0iz_zq/how-to-put-focus-at-the-end-of-an-input-with-react-js
J'ai le même problème mais j'ai aussi une animation, alors mon collègue suggère d'utiliser window.requestAnimationFrame
c'est l'attribut ref de mon élément:
ref={(input) => {input && window.requestAnimationFrame(()=>{input.focus()})}}
La réponse la plus simple consiste à ajouter le ref = "un nom" dans l'élément de texte de saisie et à appeler la fonction ci-dessous.
componentDidMount(){
this.refs.field_name.focus();
}
// here field_name is ref name.
<input type="text" ref="field_name" />
Avertissement: ReactDOMComponent: n'accédez pas à .getDOMNode () d'un noeud DOM; utilisez plutôt le nœud directement. Ce nœud DOM a été rendu par
App
.
Devrait être
componentDidMount: function () {
this.refs.nameInput.focus();
}
Pour déplacer le focus sur un élément nouvellement créé, vous pouvez stocker l'ID de l'élément dans l'état et l'utiliser pour définir autoFocus
. par exemple.
export default class DefaultRolesPage extends React.Component {
addRole = ev => {
ev.preventDefault();
const roleKey = this.roleKey++;
this::updateState({
focus: {$set: roleKey},
formData: {
roles: {
$Push: [{
id: null,
name: '',
permissions: new Set(),
key: roleKey,
}]
}
}
})
}
render() {
const {formData} = this.state;
return (
<GridForm onSubmit={this.submit}>
{formData.roles.map((role, idx) => (
<GridSection key={role.key}>
<GridRow>
<GridCol>
<label>Role</label>
<TextBox value={role.name} onChange={this.roleName(idx)} autoFocus={role.key === this.state.focus}/>
</GridCol>
</GridRow>
</GridSection>
))}
</GridForm>
)
}
}
De cette façon, aucune des zones de texte ne se concentre sur le chargement de la page (comme je le souhaite), mais lorsque vous appuyez sur le bouton "Ajouter" pour créer un nouvel enregistrement, celui-ci devient actif.
Étant donné que autoFocus
ne "s'exécute pas" à nouveau à moins que le composant ne soit remonté, je n'ai pas besoin de désassembler this.state.focus
(c'est-à-dire qu'il ne gardera pas le focus tant que je mettrai à jour d'autres états).
Après avoir essayé beaucoup d’options ci-dessus sans succès, j’ai trouvé que c’était comme j’étais disabling
puis enabling
l’entrée qui avait entraîné la perte du focus.
J'avais un accessoire sendingAnswer
qui désactivait l'entrée pendant l'interrogation du backend.
<Input
autoFocus={question}
placeholder={
gettingQuestion ? 'Loading...' : 'Type your answer here...'
}
value={answer}
onChange={event => dispatch(updateAnswer(event.target.value))}
type="text"
autocomplete="off"
name="answer"
// disabled={sendingAnswer} <-- Causing focus to be lost.
/>
Une fois que j'ai retiré l'accessoire handicapé, tout a recommencé à fonctionner.
Lire la quasi-totalité de la réponse mais je n'ai pas vu de getRenderedComponent().props.input
Définissez vos références de saisie de texte
this.refs.username.getRenderedComponent().props.input.onChange('');
Version mise à jour que vous pouvez vérifier ici
componentDidMount() {
// Focus to the input as html5 autofocus
this.inputRef.focus();
}
render() {
return <input type="text" ref={(input) => { this.inputRef = input }} />
})