javascript - React.js - vstup ztrácí fokus při opětovném renderování
Právě píšu do textového vstupu a v události onChange volám setState, takže React znovu renderuje mé uživatelské rozhraní. Problém je v tom, že textový vstup vždy ztrácí fokus, takže ho musím znovu zaměřit po každém písmenu :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>
);
}
});
Odpověď č. 1
Bez toho, aniž bych viděl zbytek vašeho kódu, je to jen odhad. Když vytvoříte EditorContainer, určete pro komponentu jedinečný klíč:
<EditorContainer key="editor1"/>Když dojde k opětovnému vykreslení, pokud se objeví stejný klíč, řekne to Reactu, aby nepřepisoval a znovu nevytvářel pohled, místo toho použil znovu existující. Pak by měl vybraný prvek zachovat fokus.
Odpověď č. 2
Stále se sem vracím znovu a znovu a na konci vždy najdu řešení něčeho jinde. Takže to zde zdokumentuji, protože vím, že na to znovu zapomenu!
Důvod, proč input v mém případě ztrácel fokus, byl ten, že jsem při změně stavu znovu vykresloval input.
Chybový kód:
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>
)
}
}
Takže problém je v tom, že vždy začínám kódovat všechno na jednom místě, abych rychle otestoval, a později to rozděluji na samostatné moduly. Ale zde se tato strategie obrací proti mně, protože aktualizace stavu při změně vstupu spouští funkci render a fokus se ztrácí.
Oprava je jednoduchá, provést modularizaci od začátku, jinými slovy, „Přesunout komponentu Input z funkce render“
Opravený kód
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>
)
}
}
Odkaz na řešení: https://github.com/styled-components/styled-components/issues/540#issuecomment-283664947
Odpověď č. 3
Měl jsem stejné příznaky s hooky. Přesto můj problém byl definovat komponentu uvnitř rodiče.
Špatně :
const Parent =() => {
const Child = () => <p>Child!</p>
return <Child />
}
Správně :
const Child = () => <p>Child!</p>
const Parent = () => <Child />
Odpověď č. 4
Pokud je to problém v rámci React routeru <Route/>, použijte vlastnost render místo component.
<Route path="/user" render={() => <UserPage/>} />
Ztráta fokusu nastává, protože vlastnost component používá React.createElement pokaždé místo toho, aby jen znovu vykreslila změny.
Podrobnosti zde: https://reacttraining.com/react-router/web/api/Route/component
Odpověď č. 5
Má odpověď je podobná tomu, co řekl @z5h.
V mém případě jsem použil Math.random() k vygenerování unikátního key pro komponentu.
Myslel jsem si, že key se používá pouze k vyvolání znovuvykreslení toho konkrétního komponentu, spíše než k přerenderování všech komponent v tom poli (ve svém kódu vracím pole komponent). Nevšiml jsem si, že se používá k obnovení stavu po znovuvykreslení.
Odstranění toho pro mě fungovalo.
Odpověď č. 6
Co jsem udělal, bylo prostě změnit vlastnost value na defaultValue a druhou změnou byla změna události onChange na onBlur.
Odpověď č. 7
Použití atributu autoFocus na element input může fungovat jako řešení v situacích, kdy je jen jedno pole, na které je potřeba se zaměřit. V takovém případě by atribut key nebyl nutný, protože se jedná pouze o jeden element, a navíc byste se nemuseli obávat rozdělování elementu input do samostatné komponenty, aby nedošlo ke ztrátě fokusu při opětovném renderování hlavní komponenty.
