Vyhledávání na webu

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.

Související články