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

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

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

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

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

Q&A

解決済

2回答

1194閲覧

【React】TypeError: ** is not a function

southernX

総合スコア5

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

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

0グッド

0クリップ

投稿2019/08/14 14:41

Reactでのエラー

reactでTodoリストを作っています。入力した内容がリストで表示されます。

実現したい事としてはこの通りです。
inputタグ内で入力した内容がhandleChangeメソッドによりstateのinputに更新されます。

そして送信ボタンを押したら、handleSubmitメソッドによりstate.inputの内容がtoDoList(配列)に入れられます。

もしtoDoListに要素が一つでもあるなら、それをリストとしてレンダリングします。

###起こった問題

しかし、送信ボタンを押すと二つの問題が発生しました。

まず、フォームに入力して「追加」ボタンを「一度」押すとリストが消えてしまうことです。

cccと入力してボタンを押してみました。

次にこの状態でもう一度ボタンを押すと次のエラーが発生しました。

以下がhandleSubmitメソッド内で起こったエラーです。

エラーメッセージ

TypeError: Todo.push is not a function

該当のソースコード

indexjs

1import React from 'react'; 2import ReactDOM from 'react-dom'; 3import './index.css'; 4// import App from './App'; 5import * as serviceWorker from './serviceWorker'; 6 7class Todo extends React.Component { 8 constructor(props) { 9 super(props); 10 this.state = { 11 input: '', 12 toDoList: ["aaa", "bbb"], 13 } 14 } 15 16 17 handleSubmit(e) { 18 e.preventDefault(); 19 const input = this.state.input; 20 const Todo = this.state.toDoList; 21 this.setState({ 22 toDoList: Todo.push(input), 23 }); 24 } 25 26 27 handleChange(event) { 28 const input = event.target.value; 29 this.setState({ 30 input: input, 31 }); 32 } 33 34 render(){ 35 var toDoList; 36 if (this.state.toDoList.length > 1) { 37 toDoList = this.state.toDoList.map((list) => { 38 return ( 39 <li>{list}</li> 40 ); 41 }); 42 } 43 44 return( 45 <div className="container"> 46 <div className="Todo">Todoリスト</div> 47 <ul> 48 {toDoList} 49 </ul> 50 <form onSubmit={(e) => this.handleSubmit(e)}> 51 <input type="text" onChange={(event) => this.handleChange(event)}/> 52 <input type="submit" value="追加"/> 53 </form> 54 55 </div> 56 ) 57 } 58} 59 60ReactDOM.render( 61 <Todo />, 62 document.getElementById('root') 63);

試したこと

toDoListは配列であることを確かめるために試しに"aaa","bbb"という文字列を入れてみました。するとこれは正しく表示されました。renderメソッド内ではtoDoList.mapが動いているようです。

stateの定義の仕方が悪いのかと思った時はstate: new Arrayにしてみましたが解決しませんでした。

handleSubmit内でstate.toDoListを変数に代入する際、sliceメソッドで使ってみましたがすぐに的外れであることがわかりました。

this.state.toDoListは確かに配列で、pushメソッドも問題なく使えるはずなのですが・・・

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

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

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

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

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

guest

回答2

0

ベストアンサー

こんにちは

以下は MDN の push メソッドの説明 からの引用です。

push() メソッドは、配列の末尾に 1 つ以上の要素を追加することができます。また戻り値として新しい配列の要素数を返します。

上記のとおり、 push メソッドは、要素が追加された後の配列の長さを返します。なので、ご質問のコードだと、1回目の「追加」ボタンをクリックしたのときの

javascript

1this.setState({ 2 toDoList: Todo.push(input), 3 });

によって、 this.state.toDoList には、1つ要素の追加された配列の長さが入るので、 3 という数値が設定されます。
そのため、 render の以下の部分

javascript

1 if (this.state.toDoList.length > 1) {

で、 this.state.toDoList.length は undefined になり、 if が判定する条件は false になって、 <ul> の中身が作られないために、画面上では、既存のリストアイテムも消えてしまいます。

さらに続けて「追加」ボタンをクリックしたときは、

javascript

1const Todo = this.state.toDoList;

によって const Todo には 3 という数値が入ってきて、

javascript

1Todo.push(input)

を実行しようとしますが、3という数値にはpushというメソッドはないので、

TypeError: Todo.push is not a function

というエラーになります。
修正の方法ですが、新しい this.state.toDoList を setState する箇所の

修正前:

javascript

1toDoList: Todo.push(input),

を、たとえば以下のように修正します。

修正後:

javascript

1toDoList: [...Todo, input],

上記の一行の修正で、とりあえずは意図通り動くようになると思います。

さらに、ちょっとリファクタさせて頂けるならば、this.state.toDoList のほうも、同じ名前の toDoList という変数に入れるようにすれば、分割代入を使って以下のように書けます。

javascript

1 handleSubmit(e) { 2 e.preventDefault(); 3 const { input, toDoList } = this.state; 4 this.setState({ 5 toDoList: [...toDoList, input], 6 }); 7 }

あるいは、一時的な変数に入れないで、以下のようにも書けます。

javascript

1 handleSubmit(e) { 2 e.preventDefault(); 3 this.setState({ 4 toDoList: [ 5 ...this.state.toDoList, 6 this.state.input 7 ], 8 }); 9 }

上記のように、 this.setState するときに、既存の state の何らかのプロパティの配列に追加したり、あるいはstateのあるプロパティはオブジェクトで、それのあるプロパティだけを変えたりするときに、スプレッド構文 ... はよく使われます。

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

投稿2019/08/14 15:37

編集2019/08/14 16:05
jun68ykt

総合スコア9058

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

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

southernX

2019/08/14 16:11

解決しました! jsでのpushは数値を返すのですね。代わりにスプレッド構文で配列を更新することも初めて知りました。勉強になりました。 スッキリしました。丁寧な回答ありがとうございます。
jun68ykt

2019/08/14 16:13

どういたしまして。 解決されたとのことで、よかったです ????
guest

0

クラス名と変数名がかぶってるからじゃないですかね?


追記
これ

Javascript

1class Todo extends React.Component {

Javascript

1 const Todo = this.state.toDoList;

これ

投稿2019/08/14 14:46

編集2019/08/14 14:50
gentaro

総合スコア8949

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

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

gentaro

2019/08/14 16:29

あぁ、ぱっと見てアレ?と思ったんですが、ハズレでしたか。 まぁ一般的によろしくない事なので、名前は変えたほうがいいっすよ。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問