React.jsフォームコンポーネントで状態または参照を使用しますか?


116

私はReact.jsから始めて、簡単なフォームを作成したいのですが、ドキュメントでそれを行う2つの方法を見つけました。

最初のものは使用している参考文献を

var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    // TODO: send request to the server
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
    return;
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

そして2番目はReactコンポーネント内のstateを使用しています:

var TodoTextInput = React.createClass({
  getInitialState: function() {
    return {
      value: this.props.value || ''
    };
  },

  render: function() /*object*/ {
    return (
      <input className={this.props.className}
      id={this.props.id}
      placeholder={this.props.placeholder}
      onBlur={this._save}
      value={this.state.value}
      />
    );
  },

  _save: function() {
    this.props.onSave(this.state.value);
    this.setState({value: ''
  });
});

2つの代替案が存在する場合、その長所と短所はわかりません。ありがとう。


ここで何か不足していますか?イベントオブジェクトを使用してフォームの値を取得しませんか?これがフォームを最初に使用する唯一の理由のようです。デフォルトの送信動作を使用しておらず、入力に参照がある場合は、フォームにラップする必要はありません。
NectarSoft 2016年

回答:


143

短いバージョン:参照を避けます。


これらは保守性が悪く、レンダリングが提供するWYSIWYGモデルのシンプルさの多くを失っています。

フォームがあります。フォームをリセットするボタンを追加する必要があります。

  • refs:
    • DOMを操作する
    • renderは、3分前のフォームの外観を表します
  • 状態
    • setState
    • renderはフォームがどのように見えるかを説明します

入力にCCV番号フィールドがあり、アプリケーション内に数値である他のいくつかのフィールドがあります。ここで、ユーザーに数字のみを入力させる必要があります。

  • refs:
    • onChangeハンドラーを追加します(これを回避するために参照を使用していませんか?)
    • 数値でない場合、onChangeでdomを操作します
  • 状態
    • あなたはすでにonChangeハンドラを持っています
    • ifステートメントを追加し、無効な場合は何もしない
    • renderは、異なる結果を生成する場合にのみ呼び出されます

ええ、気にしないでください。首相は、それが無効な場合は、赤いボックスシャドウを実行するように要求します。

  • refs:
    • onChangeハンドラーがforceUpdateなどを呼び出すだけですか?
    • レンダー出力をベースにして...ハァッ?
    • レンダリングで検証する値はどこにありますか?
    • 要素のclassName domプロパティを手動で操作しますか?
    • 道に迷いました
    • 参照なしで書き換えますか?
    • マウントされている場合はレンダーでdomから読み取り、そうでない場合は有効と見なしますか?
  • 状態:
    • ifステートメントを削除する
    • this.stateに基づいてレンダーを検証する

親に制御を戻す必要があります。データは小道具になり、変更に対応する必要があります。

  • refs:
    • componentDidMount、componentWillUpdate、およびcomponentDidUpdateを実装します
    • 以前の小道具を手動で比較する
    • 最小限の変更セットでdomを操作する
    • ねえ!反応で反応を実装しています...
    • もっとありますが、私の指は痛いです
  • 状態:
    • sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js

人々は、リファレンスを状態に保つよりも「簡単」であると考えています。これは最初の20分間は当てはまるかもしれませんが、その後の私の経験では当てはまりません。「確かに、いくつかのコンポーネントを書き換えるだけ」ではなく、「ええ、5分で完了します」と言う立場に自分を置きます。


3
sed -e 's / this.state / this.props /' 's / handleChange / onChange /' -i form.jsについてもう少し説明していただけますか?
gabrielgiussi

1
いいえ、domの実際の変更を意味します。 React.findDOMNode(this.refs.foo)。たとえば変更した場合、this.refs.foo.props.bar何も起こりません。
ブリガンド2015

1
たとえば、それをに <input onChange={this.handleChange} value={this.state.foo} />変更した<input onChange={this.props.handleChange} value={this.props.foo} />場合、またはハンドル変更関数を変更して、小道具のコールバックを呼び出す場合。いずれにせよ、それはいくつかの小さな明らかな変更です。
ブリガンド2015

4
あなたの答えを少し混乱させるのが私だけかどうかはわかりません。ポイントを明確にするいくつかのコードサンプルを見せていただけますか?
リシャブ2015

2
画面に50以上の入力があると、状態が変化するたびにレンダリングが行われることは望ましくありません。それぞれinputが独自の状態を維持する各フィールドをコンポーネント化するのが理想的です。ある時点で、これらのさまざまな独立状態をいくつかのより大きなモデルと調整する必要があります。たぶん、タイマーに自動保存があるか、節約するだけcomponentWillUnmountです。これがrefs理想的な場所です。調整中にstate、それぞれから値を取得しますrefが、どれも賢くありません。ほとんどの場合、私stateはその答えに同意しますが、多数のinputs場合、適切なrefsパターンを使用することはパフォーマンスの恩恵です
lux

105

「refを使用しない」理由として上記の回答を引用する人が何人かいるのを見たことがありますが、私(および私が話を聞いた他の数人のReact開発者)に意見を述べたいと思います。

「参照を使用しない」という感情は、コンポーネントインスタンスでの参照の使用に関しては正しいです。つまり、コンポーネントインスタンスを取得してそれらのメソッドを呼び出す方法としてrefを使用しないでください。これは参照を使用する誤った方法であり、参照がすぐに南下する場合です。

refを使用する正しい(そして非常に便利な)方法は、それらを使用してDOMから値を取得する場合です。たとえば、その入力に参照をアタッチする入力フィールドがある場合、後で参照を介して値を取得するだけで問題ありません。この方法がない場合、ローカル状態またはフラックスストアのいずれかで入力フィールドを最新の状態に保つために、かなり調整されたプロセスを実行する必要がありますが、これは不要のようです。

2019編集:こんにちは、未来の友達。数年前に述べたものに加えて^、React Hooksを使用すると、refはレンダリング間でデータを追跡するための優れた方法でもあり、DOMノードの取得だけに限定されません。


3
最後の段落は完全に理にかなっていますが、2番目の段落を明確にできますか?コンポーネントインスタンスを取得し、正しくないと見なされるメソッドを呼び出す具体的な例は何ですか?
Danny Libin、2016年

2
私はこれに同意します。フィールドの値の検証や操作を行う必要がない限り、私はrefを使用しています。プログラムで変更または値の変更を検証する必要がある場合は、状態を使用します。
Christopher Davies

1
私もこれに同意します。発見段階で、私はナイーブで多数の入力がある画面に意図的に近づきました。IDをキーとするマップ(状態)に格納されているすべての入力値。言うまでもなく、チェックボックスのクリックが理想的ではなかったなどの小さなUI変更で状態を設定し、50以上の入力(一部のマテリアルUI、重い!)をレンダリングするため、パフォーマンスが低下しました。独自の状態を維持できる各入力をコンポーネント化することは、適切なアプローチのようです。調整が必要な場合は、をピアしrefsて状態値を取得します。本当にいい模様のようです。
lux 2016年

2
同意します。受け入れられた答えは私の意見では曖昧すぎます。
James Wright

同意する。これにより、一般的なフォームコンポーネントを設計する際に、制御されたコンポーネントや管理フォーカス、エラー処理などの問題点が明らかになります。実際には、クリーンなアーキテクチャを持つことはできません。必要に応じてご相談ください。コンポーネントを参照に移動しています。
kushalvm

6

TL; DR一般的に言えば、refsReactの宣言的な哲学に反するため、最後の手段として使用する必要があります。state / props可能な限り使用してください。


refsvsを使用する場所を理解するためにstate / props、Reactが従う設計原則のいくつかを見てみましょう。

あたりが反応ドキュメントをについてrefs

宣言的に行うことができるものには、参照を使用しないでください。

脱出ハッチに関するReactの設計原則

アプリの構築に役立つパターンが宣言的に表現するのが難しい場合は、命令型のAPIを提供します。(そして、彼らはここで参照にリンクしています)

つまり、Reactのチームは、反応的/宣言的な方法で実行できるあらゆるものを回避refsして使用することを提案していstate / propsます。

@タイラーマクギニスは非常に良い答えを提供し、それも述べています

refを使用する正しい(そして非常に便利な)方法は、それらを使用してDOMから値を取得する場合です...

それは可能ですが、Reactの哲学に反することになります。入力に値がある場合、それは間違いなくからのものstate / propsです。コードの一貫性と予測可能性を維持するには、state / propsそこにも固執する必要があります。私はrefs時々あなたにもっと速い解決策を与えるという事実を認めます、それであなたが概念の証明をするならば、速くて汚いことは許容できます。

これにより、いくつかの具体的な使用例残りますrefs

フォーカス、テキスト選択、またはメディア再生の管理。命令型アニメーションのトリガー。サードパーティのDOMライブラリとの統合。


5

この投稿は古いです。

その件について、私の小さな経験を共有します。

私は、多くの「動的」入力と多くのキャッシュされたデータが含まれる大きなコンポーネント(414行)で作業していました。(私はページで一人で作業しているのではなく、コードの構造がおそらくより良く分割される可能性があると私の感覚は教えてくれますが、それはポイントではありません(まあ、それは可能ですが、私はそれを扱っています)

最初に状態を操作して、入力の値を処理しました。

  const [inputsValues, setInputsValues] = useState([])
  const setInputValue = (id, value) => {
    const arr = [...inputsValues]
    arr[id] = value
    setInputsValues(arr)
  }

そしてもちろん入力では:

value={inputsValues[id] || ''}
onChange={event => setInputValue(id, event.target.value)}

レンダリングが非常に重く、入力の変更が****と途切れがちでした(キーを押したままにしないでください。テキストは一時停止後にのみ表示されます)

refsを使用してこれを回避できると確信していました。

このようになった:

  const inputsRef = useRef([])

そして入力で:

ref={input => (inputsRef.current[id] = input)}

[私の場合、入力はMaterial-UI TextFieldだったので、

inputRef={input => (inputsRef.current[id] = input)}

]

これのおかげで、レンダリングは行われず、入力はスムーズで、機能は同じように機能します。サイクルと計算を節約するので、エネルギーも節約できます。地球のためにそれを行うx)

私の結論:入力値のuseRefも必要になる可能性があります。

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