React.jsでボタンを無効にする方法


84

私はこのコンポーネントを持っています:

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>
    );
}

}

入力値が空のときにボタンを無効にしたい。しかし、上記のコードは機能しません。それは言う:

add-item.component.js:78 Uncaught TypeError:undefinedのプロパティ 'value'を読み取れません

を指していdisabled={!this.input.value}ます。ここで何が間違っているのでしょうか?renderメソッドの実行時にrefがまだ作成されていないのではないかと思います。もしそうなら、回避策は何ですか?

回答:


109

refsDOMを直接読み取るため、使用はベストプラクティスではありませんstate。代わりに、Reactを使用することをお勧めします。また、コンポーネントが再レンダリングされず、初期状態のままであるため、ボタンは変更されません。

イベントリスナーとsetState一緒に使用してonChange、入力フィールドが変更されるたびにコンポーネントを再度レンダリングできます。

// 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} />

これが実際の例です:

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>


これが正解です!入力の変更時に更新するには内部状態を使用する必要があり、ボタンはこれをチェックするだけです。+1
Michael Giovanni Pumo 2017年

this.stateには、UIを再度レンダリングするという制限があるため、子コンポーネントのテキストボックスに入力していて、onChangeイベントにバインドしている場合、テキストボックスからフォーカスが失われます。同じコンポーネントにある場合は問題ありませんが、子コンポーネントで使用するとフォーカスが失われます。
動的

@Dynamicそれは起こらないはずです。その実例はありますか?
ファビアンシュルツ2017

参考までに、これはクロスブラウザフレンドリーではありません。多くのブラウザは、falseに設定されている場合でも、無効の存在をtrueとして解釈します。文字通り、無効になっている属性の存在をチェックするだけです。クロスブラウザ対応にするには、disabled属性を削除する必要があります。
アドリアーノポリス

@Adrianopolis Reactは、disabled属性がに設定されている場合、DOMから属性を削除しますfalse—これはクロスブラウザーフレンドリーです。
ファビアンシュルツ

9

HTMLでは、

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

それらはすべて、空でない文字列に対してtrueを返すため、disabled = "true"に要約されます。したがって、falseを返すには、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>
    );
}

スタックオーバーフローに支持的な答えのオプションがある場合、私はこの答えを選択します
Feras


4

Reactでコンポーネントのレンダリングを制御する典型的な方法はいくつかあります。 ここに画像の説明を入力してください

ただし、ここではこれらのいずれも使用していません。コンポーネントの子の基になる名前空間にrefを使用しただけです。

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.inputrefコールバックが呼び出されるまでは未定義です。this.inputコンストラクターで初期値に設定してみてください。

refsに関するReactのドキュメントから私の強調:

コールバックは、コンポーネントがマウントまたはマウント解除された直後実行されます


0

同様の問題が発生しました。これらを実行するためにフックは必要ありません。条件付きレンダリングを作成できますが、それでも正常に機能します。

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

0

追加するだけです:

<button disabled={this.input.value?"true":""} className="add-item__button" onClick={this.add.bind(this)}>Add</button>

0

これに対する非常に簡単な解決策は、useRefフックを使用することです

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>

同様に、を使用してボタンを有効にすることができます buttonRef.current.disabled = false

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.