質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

475閲覧

(React.js) Sign up機能 with real time validationにてstateが更新されない

kazoogon

総合スコア281

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2018/10/14 18:55

編集2018/10/15 03:08

今していること

react.jsを使用し、リアルタイムバリデーション機能の付いたユーザー登録画面の作成

質問

setStateでstateを更新しようとしてもうまくいかない
(inputで入力された値を更新しようとしています)

該当部分は下記コード内にて記載いたしました。

コード

(関係ないと思われる部分は省いています)

import React, { Component } from 'react'; class Register extends Component { constructor(props) { super(props); this.state = { firstName: { value: '', status: '' }, lastName: { value: '', status: '' }, email: { value: '', status: '' }, password: { value: '', status: '' }, password2: { value: '', status: '' } }; } tmpClassName = tmp => { const prefix = 'form-control '; switch (tmp) { case '': return prefix + ''; case true: return prefix + 'is-valid'; case false: return prefix + 'is-invalid'; } }; onChange = e => { const currentName = e.target.name; const currentValue = e.target.value; //ここで、valueが更新されない、というか消える this.setState({ [currentName]: { value: currentValue } }); switch(currentName){ case 'firstName': if(currentValue !== '' && currentValue.length >= 2) { this.setState({ firstName: { status: true } }) }else{ this.setState({ firstName: { status: false } }) } break; case 'lastName': if(currentValue !== '' && currentValue.length >= 2) { this.setState({ lastName: { status: true } }) }else{ this.setState({ lastName: { status: false } }) } break; case 'email': const invalidEmail = currentValue.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*$/); if(invalidEmail && currentValue !== ''){ this.setState({ email: { status: true } }) }else{ this.setState({ email: { status: false } }) } break; case 'password': if(currentValue.length >= 6){ this.setState({ password: { status: true } }) }else{ this.setState({ password: { status: false } }) } break; case 'password2': if(currentValue.length >= 6 && currentValue == this.state.password.value){ this.setState({ password2: { status: true } }) }else{ this.setState({ password2: { status: false } }) } break; } }; onSubmit = e => { e.preventDefault(); } render() { return ( <div className="row register offset-md-2 col-md-8 col-xs-12"> <form onSubmit={ this.onSubmit }> <fieldset> <h1>Sign Up</h1> <div className="form-group name"> <input type="firstName" className={this.tmpClassName(this.state.firstName.status)} name="firstName" placeholder="First Name" value={this.state.firstName.value} onChange={this.onChange} minLength="2" required /> <input type="lastName" className={this.tmpClassName(this.state.lastName.status)} name="lastName" placeholder="Last Name" value={this.state.lastName.value} onChange={this.onChange} minLength="2" required /> </div> <div className="form-group"> <input type="email" className={this.tmpClassName(this.state.email.status)} name="email" aria-describedby="emailHelp" placeholder="Email" value={this.state.email.value} onChange={this.onChange} required /> <small id="emailHelp" className="form-text text-muted"> We'll never share your email with anyone else. </small> </div> <div className="form-group"> <input type="password" className={this.tmpClassName(this.state.password.status)} name="password" placeholder="Password" value={this.state.password.value} onChange={this.onChange} minLength="6" maxLength="100" required /> </div> <div className="form-group"> <input type="password" className={this.tmpClassName(this.state.password2.status)} name="password2" placeholder="Confirm Password" value={this.state.password2.value} onChange={this.onChange} minLength="6" maxLength="100" required /> </div> <button type="submit" /*statusのlength取って、classを加えていく感じやな*/ className={`btn btn-primary ${this.state.firstName.status? 'quarter' : ''} + ${this.state.lastName.status? 'half' : ''} + ${this.state.email.status? 'three-quarters' : ''}` } disabled > Submit </button> </fieldset> </form> </div> ); } } export default Register;

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jun68ykt

2018/10/14 22:49

こんにちは。回答に書いたとおり「コード全体を見ないとはっきりしない」ところがあります。特に、(1) tmpClassName はどのようなことをしているのか?(2) status によって切り替わる各 input のとりえるクラス名とそれらによって当たるスタイル。これら2点が不明だとソースコードの中にコメントで書いてある、 "(というか消える)"  がどういうことか回答者各位に伝わりにくいと思われます。
kazoogon

2018/10/15 03:08

コード追記いたしました、よろしくお願いいたします。
jun68ykt

2018/10/15 04:39

追記ありがとうございます。tmpClassName の問題について回答のほうのコメントに書きました。
guest

回答1

0

ベストアンサー

こんにちは。

コード全体を見ないとはっきりしないのですが、ぱっと見で思ったのは、ご質問のコードだと、this.setStateするときに当該currentNamestatusプロパティが失われてしまうので、そのために意図した動作になっていないのでは? ということです。

ですので、this.setStateしているところを、以下のようにしてみるといかがでしょうか?

修正前:

javascript

1this.setState({ 2 [currentName]: { 3 value: currentValue 4 } 5 });

修正後:

javascript

1this.setState({ 2 [currentName]: { 3 value: currentValue, 4 status: this.state[currentName].status 5 } 6 });

上記の修正では this.setStateしたときに当該currentNamestatusプロパティは変わらないようにしています。

以上参考になれば幸いです。

追記

kazoogon 2018/10/15 12:10

回答ありがとうございます。
これは例えばプロパティが10個あったら、setStateする度に10個書かないといけないということ?? になるんですかね??

上記に回答します。

プロパティが10個あったら

というのは、this.state の各currentName の値であるオブジェクトに10個のプロパティがあり、たとえば

javascript

1 2this.state = { 3 firstName: { 4 value: '', 5 status: '', 6 prop1: '', prop2: '', prop3: '', prop4: '', 7 prop5: '', prop6: '', prop7: '', prop8: '', 8 } 9}

というものだった場合、setStateするときに、1個のプロパティは変更するとして、残りの変更したくない9個のプロパティについて、すべて先の回答の status: this.state[currentName].status のようなプロパティのコピーを個別に書かなければならないか? というご質問だと思います。(違っていたら、またコメント頂ければと思います)

回答としては、その必要はなく、...によるスプレッドを使って以下のように書けばよいかと思います。

javascript

1this.setState({ 2 firstName: { 3 ...this.state.firstName, 4 value: currentValue, 5 } 6 });

上記により、 first の内容としては、valueだけが更新されており他は変更なしのオブジェクトで setStateされます。

追記2

ご質問に挙げられているコードから始めて、意図通り動くようにし、入力値のバリデーションを関数化したものを以下のレポジトリ

に上げましたので、もしよければ git cloneして頂くか、ダウンロードのうえ、内容をご確認ください。
以下、このレポジトリに入れたソースについて説明します。

(1) 最初のコミットでは、ご質問に挙げられている Register をそのままコピペして Register.js を作成し、これだけを表示する index.js を作成しました。

(2) 次のコミット、「一度のsetStateでvalueとstateを更新するように修正」にて、 onChange の中で一度だけsetStateするようにしています。これで、とりあえず意図通り動くようになるかと思います。

(3) 入力値のバリデーションを関数化 することで、onChange を以下のように短くしました。

javascript

1 onChange = e => { 2 const { name, value } = e.target; 3 4 let status = validate(name, value); 5 if (name === 'password2') 6 status = status && this.state.password.value === value; 7 8 this.setState( { [name]: { value, status } }); 9 };

以上です。

投稿2018/10/14 22:39

編集2018/10/15 12:57
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazoogon

2018/10/15 03:10

回答ありがとうございます。 これは例えばプロパティが10個あったら、setStateする度に10個書かないといけないということ?? になるんですかね??
jun68ykt

2018/10/15 04:36

コメントありがとうございます。 > 10個書かないといけないということ?? についての返答を、回答のほうに追記しました。 また、tmpClassName のソースコードを回答に追記、ありがとうございます。 tmpClassName を見て、 > というか消える の原因は、tmpClassNameの中で、バリデーションが成功したときに this.setState({ firstName: { status: true } }) としており、 value が無くなってしまうからと思われます。 コード全体として、回答のほうに追記したスプレッド構文を使うなどして、更新したいプロパティ以外は変更されずに残るようにsetState しているところを見直せば、完成に近づくと思われます。 また不明点、解決できない点などあればコメントからお知らせ頂ければと思います。
kazoogon

2018/10/15 06:01

status: this.state[currentName].status を追記してみましたが、input内に文字が反映されない状態になっていますね。。
jun68ykt

2018/10/15 11:52

こんばんは。あらためてソースを見直してみましたが、原因はonChange の中で、 value を設定する setState と status を設定するsetStateとで、2回 setState していることのようです。のちほど回答に追記します。
jun68ykt

2018/10/15 12:59

ご質問に挙げられているコードから始めて、意図通り動くようにし、入力値のバリデーションを関数化したものを作りました。回答のほうに追記2を書きましたのでご覧ください。
kazoogon

2018/10/15 17:48

今回もありがとうございました。 まさかここまでコードが短くなるとは驚きです、どんな教科書よりも役に立つ物を与えてくださり感謝の気持ちでいっぱいです
jun68ykt

2018/10/15 21:38

どういたしまして。お役に立てたようでよかったです ????
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問