0

そのため、React アプリケーションで問題が発生しましsetState()た。1 つのメソッドで複数の呼び出しを行い、状態が設定された後にコードを実行する必要がある特定のケースに遭遇しました。以下のコードは、Web サイトにアカウントを追加するために使用されるダイアログ ボックスです。

import React from 'react';
import Dialog from 'material-ui/Dialog';
import FlatButton from 'material-ui/FlatButton';
import TextField from 'material-ui/TextField';

/**
 * A modal dialog can only be closed by selecting one of the actions.
 */
export default class NewAcctDia extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
      userError: null,
      passError: null,
      passConfirmError: null,
    }

    this.handleOpen = this.handleOpen.bind(this);
    this.handleClose = this.handleClose.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleOpen() {
    this.setState({open: true});
  }

  handleClose() {
    this.setState({open: false});
  }

  handleSubmit() {
    if(!this.refs.user.getValue())
      this.setState({userError: "This field is required"});
    else
      this.setState({userError: null});

    if(!this.refs.pass.getValue())
      this.setState({passError: "This field is required"});
    else
      this.setState({passError: null});

    if(this.refs.pass.getValue() == this.refs.passConfirm.getValue()) {
      this.setState({passError: null});
    } else {
      this.setState({passConfirmError: "Passwords do not match"});
    }

    if(!this.state.userError && !this.state.passError && !this.state.passConfirmError)
      alert('worked');
  }

  render() {
    const actions = [
      <FlatButton
        label="Cancel"
        primary={true}
        onTouchTap={this.handleClose}
      />,
      <FlatButton
        label="Submit"
        primary={true}
        disabled={false}
        onTouchTap={this.handleSubmit}
      />,
    ];

    return (
        <Dialog
          title="Create an Account"
          actions={actions}
          modal={true}
          open={this.state.open}
          contentStyle={{width: 350}}
        >
          <TextField
            ref='user'
            floatingLabelText="Username"
            errorText={this.state.userError}
          /><br />
          <TextField
            ref='pass'
            floatingLabelText="Password"
            type="password"
            errorText={this.state.passError}
          /><br />
          <TextField
            ref='passConfirm'
            floatingLabelText="Confirm Password"
            type="password"
            errorText={this.state.passConfirmError}
          /><br />
        </Dialog>
    );
  }
}

問題はhandleSubmit()メソッドにあります。ユーザーがユーザー名とパスワードのフィールドに何かを入力したこと、およびパスワードと確認パスワードのフィールドが一致していることを確認する必要がありました。そうでない場合は、状態による変更が必要なフィールドにエラー テキストを追加します。次に、状態を調べて、エラーがあるかどうかを確認しようとしました。

残念ながら、私がすぐに理解したように、setState()関数は非同期です。つまり、最終チェックの前に状態が変更されません。コードを実行する前に状態が変化するのを待つ方法をグーグルで検索しましたが、空になりました。私は今この問題を解決し、それをスタックに載せて、他の人が私が思いついた方法の恩恵を受けるかもしれないと考えました。また、私がやっていることの長所と短所、またはよりうまくいくかもしれない提案を知りたい.

グーグルで検索すると、次のようにコールバックを送信するメソッドに出くわしましたsetState(): setState(data, callback). setState()複数の通話があったため、最初はこれがうまくいくとは思いませんでした。しかし、handleSubmit()メソッドを 3 項を使用した単一のsetState()呼び出しに変換できることに気付きました。そのようです:

handleSubmit() {
    this.setState({
      userError: (
        this.refs.user.getValue() ? null : "This field is required"
      ),
      passError: (
        this.refs.pass.getValue() ? null : "This field is required"
      ),
      passConfirmError: (
        (this.refs.pass.getValue() == this.refs.passConfirm.getValue()) ? 
          null : "Passwords do not match"
      )
    }, () => {
      if(!this.state.userError && !this.state.passError && !this.state.passConfirmError)
        alert('worked');
    })
}

状態が変更された後に匿名のコールバック関数が実行されるため、チェックが機能します。

この方法で予測される唯一の問題は、入れ子になった三項です。これは、必要に応じて非常に面倒になる可能性があるためです。これが私のプログラムに悪影響を与える可能性はありますか? または、これを解決できたより良い方法はありますか?

私の解決策で何人かの人々を助けたことを願っています。:D

4

1 に答える 1

2

ReactのドキュメントcomponentDidUpdateでは、 のコールバック パラメータの代わりに を使用することを推奨していますsetState

それでも、コードが少し乱雑に思える場合は、ローカル const を試して、次のように 1 回呼び出しますsetState

handleSubmit() {
  const {user, pass, passConfirm} = this.refs;
  const userError = user.getValue() ? null : "This field is required";
  const passError = pass.getValue() ? null : "This field is required";
  const passConfirmError = !passError && pass.getValue() === passConfirm.getValue()
    ? null
    : "Passwords do not match";

  this.setState({userError, passError, passConfirmError});

  if(!userError && !emptyPassError && !passConfirmError)
    alert('worked');
}

最後に、ドキュメントでは、文字列参照よりもコールバック参照を使用することも推奨しています。

クラスにプロパティを設定するためだけに ref コールバックを使用することは、DOM 要素にアクセスするための一般的なパターンです。現在 this.refs.myRefName を使用して参照にアクセスしている場合は、代わりにこのパターンを使用することをお勧めします。

于 2016-12-07T03:03:39.550 に答える