Jak wyłączyć przycisk w React.js


86

Mam ten komponent:

import React from 'react';

export default class AddItem extends React.Component {

add() {
    this.props.onButtonClick(this.input.value);
    this.input.value = '';
}


render() {
    return (
        <div className="add-item">
            <input type="text" className="add-item__input" ref={(input) => this.input = input} placeholder={this.props.placeholder} />
            <button disabled={!this.input.value} className="add-item__button" onClick={this.add.bind(this)}>Add</button>
        </div>
    );
}

}

Chcę, aby przycisk był wyłączony, gdy wartość wejściowa jest pusta. Ale powyższy kod nie działa. To mówi:

add-item.component.js: 78 Uncaught TypeError: Cannot read property „value” of undefined

wskazuje na disabled={!this.input.value}. Co tu robię źle? Zgaduję, że być może ref nie jest jeszcze tworzony, gdy rendermetoda jest wykonywana. Jeśli tak, jakie jest obejście?

Odpowiedzi:


116

Używanie refsnie jest najlepszą praktyką, ponieważ czyta bezpośrednio DOM, lepiej statezamiast tego użyć Reacta . Ponadto przycisk nie zmienia się, ponieważ komponent nie jest ponownie renderowany i pozostaje w swoim stanie początkowym.

Możesz używać setStaterazem z onChangedetektorem zdarzeń, aby renderować komponent ponownie za każdym razem, gdy zmieni się pole wejściowe:

// Input field listens to change, updates React's state and re-renders the component.
<input onChange={e => this.setState({ value: e.target.value })} value={this.state.value} />

// Button is disabled when input state is empty.
<button disabled={!this.state.value} />

Oto działający przykład:

class AddItem extends React.Component {
  constructor() {
    super();
    this.state = { value: '' };
    this.onChange = this.onChange.bind(this);
    this.add = this.add.bind(this);
  }

  add() {
    this.props.onButtonClick(this.state.value);
    this.setState({ value: '' });
  }

  onChange(e) {
    this.setState({ value: e.target.value });
  }

  render() {
    return (
      <div className="add-item">
        <input
          type="text"
          className="add-item__input"
          value={this.state.value}
          onChange={this.onChange}
          placeholder={this.props.placeholder}
        />
        <button
          disabled={!this.state.value}
          className="add-item__button"
          onClick={this.add}
        >
          Add
        </button>
      </div>
    );
  }
}

ReactDOM.render(
  <AddItem placeholder="Value" onButtonClick={v => console.log(v)} />,
  document.getElementById('View')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='View'></div>


To jest poprawna odpowiedź! Stan wewnętrzny powinien być użyty do aktualizacji przy zmianie wejścia i przycisk powinien po prostu to sprawdzić. +1
Michael Giovanni Pumo

this.state ma ograniczenie polegające na tym, że ponownie renderuje interfejs użytkownika, więc jeśli piszesz w polu tekstowym w składniku podrzędnym i jesteś powiązany ze zdarzeniem onChange, traci fokus z pola tekstowego. Jeśli jest w tym samym komponencie, jest w porządku, ale gdy jest używany w komponencie podrzędnym, traci fokus.
Dynamiczny

@Dynamic To nie powinno się zdarzyć. Czy masz tego działający przykład?
Fabian Schultz

Do Twojej wiadomości, to nie jest przyjazne dla różnych przeglądarek. Wiele przeglądarek nadal interpretuje obecność opcji disabled jako true, nawet jeśli jest ustawiona na false. Dosłownie po prostu sprawdza obecność wyłączonego atrybutu. Musisz usunąć wyłączony atrybut, aby był przyjazny dla różnych przeglądarek.
Adrianopolis

@Adrianopolis React usuwa disabledatrybut z DOM, jeśli jest ustawiony na false- jest to przyjazne dla różnych przeglądarek.
Fabian Schultz

13

W HTML

<button disabled/>
<buttton disabled="true">
<buttton disabled="false">
<buttton disabled="21">

Wszystkie sprowadzają się do disabled = "true", ponieważ zwraca prawdę dla niepustego ciągu. Dlatego w celu zwrócenia fałszu należy przekazać pusty ciąg w instrukcji warunkowej, takiej jak this.input.value? "True": "" .

render() {
    return (
        <div className="add-item">
            <input type="text" className="add-item__input" ref={(input) => this.input = input} placeholder={this.props.placeholder} />
            <button disabled={this.input.value?"true":""} className="add-item__button" onClick={this.add.bind(this)}>Add</button>
        </div>
    );
}

jeśli przepełnienie stosu ma opcję odpowiedzi wspierającej,
wybrałbym


4

Istnieje kilka typowych metod kontrolowania renderowania komponentów w Reakcie. wprowadź opis obrazu tutaj

Ale nie użyłem tutaj żadnego z nich, po prostu użyłem ref do przestrzeni nazw podstawowych elementów potomnych składnika.

class AddItem extends React.Component {
    change(e) {
      if ("" != e.target.value) {
        this.button.disabled = false;
      } else {
        this.button.disabled = true;
      }
    }

    add(e) {
      console.log(this.input.value);
      this.input.value = '';
      this.button.disabled = true;
    }

    render() {
        return (
          <div className="add-item">
          <input type="text" className = "add-item__input" ref = {(input) => this.input=input} onChange = {this.change.bind(this)} />
          
          <button className="add-item__button" 
          onClick= {this.add.bind(this)} 
          ref={(button) => this.button=button}>Add
          </button>
          </div>
        );
    }
}

ReactDOM.render(<AddItem / > , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>


2

this.inputjest niezdefiniowana, dopóki nie refzostanie wywołana funkcja zwrotna. Spróbuj ustawić this.inputjakąś wartość początkową w konstruktorze.

Z dokumentacji React na temat referencji , nacisk mój:

wywołanie zwrotne zostanie wykonane natychmiast po zamontowaniu lub odmontowaniu komponentu


1

Miałem podobny problem, okazuje się, że nie potrzebujemy do tego hooków, możemy wykonać renderowanie warunkowe i nadal będzie działać dobrze.

<Button
    type="submit"
    disabled={
        name === "" || email === "" || password === "" ? true : false
    }
    fullWidth
    variant="contained"
    color="primary"
    className={classes.submit}>
    SignUP
</Button>

Fajne rozwiązanie, zrobiłem to samo
Simba

1

bardzo prostym rozwiązaniem jest użycie useRefhaka

const buttonRef = useRef();

const disableButton = () =>{
  buttonRef.current.disabled = true; // this disables the button
 }

<button
className="btn btn-primary mt-2"
ref={buttonRef}
onClick={disableButton}
>
    Add
</button>

Podobnie możesz włączyć przycisk za pomocą buttonRef.current.disabled = false


0

poprostu dodaj:

<button disabled={this.input.value?"true":""} className="add-item__button" onClick={this.add.bind(this)}>Add</button>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.