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

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

新規登録して質問してみよう
ただいま回答率
85.35%
React.js

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

Q&A

解決済

1回答

1070閲覧

React setStateでstateを更新できない

neginattofan

総合スコア66

React.js

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

0グッド

0クリップ

投稿2020/02/29 06:21

編集2020/02/29 06:26

Reactを使い始めたばかりです。Todoアプリのコードです。

TodoAppがアプリ全体(親)、
Totolistがやること一覧を表示しているコンポーネント(子)、
そしてTaskがそのやること一つ一つのコンポーネントです(孫)。

Taskのゴミ箱をクリックすると、this.handleClickRemoveが発火し、TodolistのhandleRemoveが呼び出され、TodoAppのcallBackRemoveTaskが呼び出され、最終的に選択したTaskを消去することができます。こちらの消去機能は動きます。

同じように、Task選択機能と、変更機能を追加しようとしましたが、画面は変わりません。

console.log()でTaskのhandleClickToggleDone、handleChangeTextの処理をみてみると、
TodoAppでsetStateでstateを何度も変更しているようにしているのですが、変更されていないことが分かりました()。

選択機能と変更機能も消去機能と同じようにした(TaskでTodoAppのstateを使えるように、propsで値を渡したり、変更されたstateをAppTodoに渡してsetStateしている)にも関わらず、
何故、変更されていないのでしょうか?

TodoApp

1コードimport React from 'react'; 2import ReactDOM from 'react-dom'; 3import TodoList from './components/TodoList'; 4class TodoApp extends React.Component { 5 6 constructor(){ 7 super(); 8 this.state = { 9 data: 10 [ 11 { 12 id: this.createHashId(), 13 text: 'sample todo1', 14 isDone: false 15 }, 16 { 17 id: this.createHashId(), 18 text: 'sample todo2', 19 isDone: true 20 } 21 ], 22 searchText: '' 23 }; 24 this.callBackRemoveTask = this.callBackRemoveTask.bind(this); 25 this.callBackChangeTask = this.callBackChangeTask.bind(this); 26 this.callBackToggleTask = this.callBackToggleTask.bind(this); 27 this.callBackAddTask = this.callBackAddTask.bind(this); 28 this.callBackSearch = this.callBackSearch.bind(this); 29 this.filterCollection = this.filterCollection.bind(this); 30 } 31 32 createHashId(){ 33 return Math.random().toString(36).slice(-16); 34 } 35 36 callBackRemoveTask(id){ 37 let data = _.reject(this.state.data, { 'id': id }); 38 this.setState({ 39 data: data 40 }); 41 } 42 callBackChangeTask(text){ 43 this.setState({ 44 text: text 45 }); 46 } 47 callBackToggleTask(isDone){ 48 this.setState({ 49 isDone: !isDone 50 }); 51 } 52 53 54 55 56 render() { 57 58 59 return ( 60 <div> 61 62 <TodoList data={data} callBackRemoveTask={this.callBackRemoveTask} callBackToggleTask={this.callBackToggleTask} callBackChangeTask={this.callBackChangeTask} /> 63 64 </div> 65 ); 66 } 67} 68 69ReactDOM.render( 70 <TodoApp/>, 71 document.getElementById('app') 72);

TodoList

1import React from 'react'; 2import Task from './Task'; 3 4export default class TodoList extends React.Component { 5 6 constructor(props){ 7 super(props); 8 this.handleRemove = this.handleRemove.bind(this); 9 this.handleToggleDone = this.handleToggleDone.bind(this); 10 this.handleChangeText = this.handleChangeText.bind(this); 11 } 12 handleRemove(id){ 13 this.props.callBackRemoveTask(id); 14 } 15 handleToggleDone(isDone){ 16 this.props.callBackToggleTask(isDone); 17 } 18 handleChangeText(text){ 19 this.props.callBackChangeTask(text); 20 } 21 render() { 22 let tasks = []; 23 for(let i in this.props.data){ 24 tasks.push(<Task key={this.props.data[i].id} 25 id={this.props.data[i].id} 26 text={this.props.data[i].text} isDone={this.props.data[i].isDone } onRemove={this.handleRemove} onToggleDone={this.handleToggleDone} onChangeText={this.handleChangeText} />); 27 } 28 29 return ( 30 <ul className="list js-todo_list"> 31 {tasks} 32 </ul> 33 ); 34 } 35}

Task

1import React from 'react'; 2import ClassNames from 'classnames'; 3import _ from 'lodash'; 4export default class Task extends React.Component { 5 6 constructor(props) { 7 super(props); 8 this.state = { 9 id: this.props.id, 10 text: this.props.text, 11 isDone: this.props.isDone, 12 editMode: false 13 }; 14 this.handleClickToggleDone = this.handleClickToggleDone.bind(this); 15 this.handleClickRemove = this.handleClickRemove.bind(this); 16 this.handleClickshowEdit = this.handleClickshowEdit.bind(this); 17 this.handleKeyUpCloseEdit = this.handleKeyUpCloseEdit.bind(this); 18 this.handleChangeText = this.handleChangeText.bind(this); 19 } 20 handleChangeText(e){ 21 this.props.onChangeText(e.target.value); 22 console.log(e.target.value); 23 } 24 handleClickToggleDone () { 25 this.props.onToggleDone(this.state.isDone); 26 console.log(this.state.isDone); 27 } 28 handleClickRemove(e) { 29 this.props.onRemove(this.state.id); 30 } 31 handleClickshowEdit() { 32 this.setState({ 33 editMode: true 34 }); 35 } 36 handleKeyUpCloseEdit(e) { 37 if(e.keyCode === 13 && e.shiftKey === true){ 38 this.setState({ 39 text: e.currentTarget.value, 40 editMode: false 41 }); 42 } 43 } 44 componentWillUnmountWillMount(){ 45 console.log('componentWillUnmountWillMount'); 46 } 47 render() { 48 // reactにはclassを付け替えする機能はないので、外部ライブラリを使う 49 const classNameLi = ClassNames({ 50 'list__item': true, 51 'list__item--done': this.state.isDone 52 }); 53 const classNameIcon = ClassNames({ 54 'fa': true, 55 'fa-circle-thin': !this.state.isDone, 56 'fa-check-circle': this.state.isDone, 57 'icon-check': true 58 }); 59 // underscoreのようなif文は使えないので、変数に前もって入れておく 60 const input = (this.state.editMode) ? 61 <input type="text" className="editText" value={this.state.text} 62 onChange={this.handleChangeText} onKeyUp={this.handleKeyUpCloseEdit}/> : 63 <span onClick={this.handleClickshowEdit}>{this.state.text}</span>; 64 65 return ( 66 <li className={classNameLi}> 67 <i className={classNameIcon} onClick={this.handleClickToggleDone} aria-hidden="true" /> 68 {input} 69 <i className="fa fa-trash icon-trash" onClick={this.handleClickRemove} aria-hidden="true" /> 70 </li> 71 ); 72 } 73} 74

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

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

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

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

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

guest

回答1

0

ベストアンサー

TodoApp の callBackChangeTask や callBackToggleTask で this.setState していますが、これは TodoApp 全体の state を更新してしまっています。

// TodoApp の state { "data": [ { "id": "0.c0ihmbr6ocu", "text": "sample todo1", // 本来は、これや "isDone": false // これや }, { "id": "0.43mkltzx7ie", "text": "sample todo2", // これや "isDone": true // これを更新したいはず } ], "searchText": "", "text": "edited todo", // 実際には、これや "isDone": true // これが追加されてる }

text や isDone は各タスクの属性ですから、callBackChangeTask や callBackToggleTask の引数にタスクの id を追加して、指定されたタスクの text や isDone を変更する必要があります。

JavaScript

1// TodoApp より 2 3 callBackChangeTask(id, text){ 4 let data = this.state.data.map(item => { 5 if (item.id === id) { 6 return { ...item, text }; 7 } else { 8 return item 9 } 10 }); 11 this.setState({ 12 data: data 13 }); 14 } 15 16 callBackToggleTask(id, isDone){ 17 let data = this.state.data.map(item => item.id === id ? { ...item, isDone: !isDone } : item); 18 this.setState({ data }); 19 }

また、Task の中で id, text, isDone を state に保存してますが、これらは props の値をそのまま使うべきです。Task の state に必要なのは editMode だけのはず。

投稿2020/02/29 07:17

編集2020/02/29 08:20
hoshi-takanori

総合スコア7901

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

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

neginattofan

2020/02/29 08:35

ありがとうございます。おかげさまで解決できました! React初心者にもわかりやすいコードで大変助かりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問