Il mio approccio sta usando ref
callback, che è una specie di onRenderComplete
di un elemento. In tale callback posso focalizzarmi (condizionatamente, se necessario) e ottenere un riferimento per la futura messa a fuoco.
Se l'input viene eseguito in modo condizionale dopo l'esecuzione di un'azione, tale callback di riferimento deve attivare un focus, poiché il riferimento non esiste ancora immediatamente dopo aver chiamato l'azione, ma solo dopo che il rendering è stato eseguito. Trattare con componentDidUpdate
per cose come focus
sembra solo un casino.
// Composer.jsx -- contains an input that will need to be focused somewhere else
class Composer extends Component {
render() {
return <input type="text" ref="input" />
}
// exposed as a public method
focus() {
this.refs.input.focus()
}
}
// App.jsx
@connect(
state => ({ isComposing: state.isComposing }),
...
)
class App extends Component {
render() {
const { isComposing } = this.props // or props, doesn't matter
return (
<div>
<button onClick={::this._onCompose}>Compose</button>
{isComposing ? <Composer ref={c => {
this._composer = c
this._composer && this._composer.focus() // issue initial focus
}} /> : null}
</div>
)
}
_onCompose() {
this.props.startComposing() // fire an action that changes state.isComposing
// the first time the action dispatches, this._composer is still null, so the ref takes care of the focus. After the render, the ref remains so it can be accessed:
this._composer && this._composer.focus() // focus if ref already exists
}
}
Perché non autoFocus
o isFocued
prop?
Come HTMLInputElement
ha value
come un oggetto di scena, ma focus()
come metodo - e non isFocused
prop - vorrei continuare ad usare metodi per gestire questo. isFocused
può ottenere un valore ma se l'utente sfuma dall'input, cosa succede a quel valore? Sarà fuori sincrono. Inoltre, come menzionato nei commenti, autoFocus
può entrare in conflitto con più componenti
Quindi come decidere tra oggetti e metodi?
Per la maggior parte dei casi gli oggetti di scena saranno la risposta. I metodi possono essere utilizzati solo in un 'fire and forget', ad esempio scrollToBottom
in una chat quando arriva un nuovo messaggio, scrollIntoView
e così via. Si tratta di comportamenti una tantum a cui il negozio non interessa e che l'utente può modificare con un'interazione, pertanto un puntello booleano non si adatta. Per tutte le altre cose, andrei con oggetti di scena.
Ecco un jsbin:
http://jsbin.com/waholo/edit?html,js,output
Redux e nodi DOM/DOM funzioni, non hanno nulla a che fare con l'altro in realtà ... non sono sicuro che come vi aspettate Redux di essere coinvolti. Perché più componenti si stanno sforzando di mettere a fuoco e che tipo di strani comportamenti stai cercando di evitare? – azium
Come afferma anteriormente, il redux è solo un modo per gestire e memorizzare lo stato dell'app. Quindi forse dovresti riformulare la tua domanda - stai chiedendo come gestire più componenti che hanno impostato focus() e quando vengono renderizzati su una pagina insieme vuoi decidere su quale di essi si focalizzi effettivamente? Immagino che dipenderebbe interamente dalla tua app!Di default è quello che è stato reso l'ultima volta credo. Considerare anche l'attributo 'autofocus'. –
Dominic, descrivi abbastanza bene le mie preoccupazioni. Componenti multipli che intendono mettere a fuoco ma solo uno vincerà. Alla fine la visualizzazione renderizzata non sarà in sincronia con la rappresentazione dichiarativa, in parte perché con una chiamata a focus() non è più dichiarativa e anche perché l'atto di ottenere la messa a fuoco causa effetti collaterali. – jpierson