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

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

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

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

ESX

ESXは、コンピュータを仮想化を実現するためのハイパーバイザ。ハードウェア上で直接動作する仮想化ソフトウェアとして知られており、「VMware vSphere」の一部として販売されています。

JavaScript

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

React.js

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

Q&A

解決済

1回答

1788閲覧

Reduxで配列の要素を削除したい

sakusaka

総合スコア14

Redux

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

ESX

ESXは、コンピュータを仮想化を実現するためのハイパーバイザ。ハードウェア上で直接動作する仮想化ソフトウェアとして知られており、「VMware vSphere」の一部として販売されています。

JavaScript

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

React.js

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

1グッド

0クリップ

投稿2019/05/04 12:26

React+Reduxで配列要素をIDで削除したい

React+Reduxを学び始めてまだ、数ヶ月です。
簡単なTodoリストを作成し、
配列に要素を追加していくことはできたのですが、
削除することができません。

削除する際にKeyとして利用したいIDをどこから取ればいいのか、
わからなく困っています。

できれば、配列のKey要素をうまくReducerに渡して、処理したいと思っています。

実際のコード

action

1export const addTodo = (todo) => { 2 return { 3 type: 'ADD_TODO', 4 // id: nextTodoId++, 5 payload: { todo: todo } 6 }; 7} 8 9export const delTodo = (deltodo) => { 10 return { 11 type: 'DEL_TODO', 12 payload: { deltodo: deltodo } 13 }; 14 } 15 16export const changeTodo = (changetodo) => { 17 return { 18 type: 'CHANGE_TODO', 19 payload: { changetodo: changetodo } 20 }; 21 }

components

1import React from 'react'; 2 3export default class Todo extends React.Component { 4 state = { 5 todo: '' 6 } 7 8 render() { 9 console.log(this.props); 10 11 // StoreのTodoからリストを生成 12 const list = this.props.todo.todoList.map((todo, index) => <li key={index}>{todo}</li>) 13 // <button onClick={() => this.props.changeTodo(this.state.todo)}>変更</button></li>) 14 15 return ( 16 <div> 17 <input type="text" onChange={elm => this.setState({ todo: elm.target.value })} /> 18 <button onClick={() => this.props.addTodo(this.state.todo)}>追加</button> 19 <button onClick={() => this.props.delTodo(this.state.deltodo)}>削除</button> 20 <ul> 21 {list} 22 </ul> 23 </div> 24 ); 25 } 26}

containers

1import { connect } from 'react-redux'; 2import * as actions from '../actions/Todo'; 3import Todo from '../components/Todo'; 4 5const mapStateToProps = state => { 6 return { 7 todo: state.todo, 8 deltodo: state.deltodo, 9 changetodo: state.changetodo, 10 } 11} 12 13const mapDispatchToProps = dispatch => { 14 return { 15 addTodo: (todo) => dispatch(actions.addTodo(todo)), 16 delTodo: (deltodo) => dispatch(actions.delTodo(deltodo)), 17 changeTodo: (changetodo) => dispatch(actions.changeTodo(changetodo)), 18 } 19} 20 21export default connect(mapStateToProps, mapDispatchToProps)(Todo)

reducer

1const initialState = { 2 todoList: [], 3 } 4 5 export const todoReducer = (state = initialState, action) => { 6 switch (action.type) { 7 case 'ADD_TODO': 8 return { 9 ...state, 10 todoList: state.todoList.concat([action.payload.todo]) 11 }; 12 case 'DEL_TODO': 13 return { 14 ...state, 15 todoList: state.todoList.concat([action.payload.todo]) 16 }; 17 case 'CHANGE_TODO' : 18 const changetodo = action.payload.changetodo; 19 const changeState = Object.assign({}, state); 20 changeState.todoList.pop(action.id, changetodo); 21 return changeState; 22 default: 23 return state; 24 } 25 };

試したこと

Reducer内で、TodoをAddする際に、action.idを付与したりしましたが、
配列として、下記のような感じとなり、うまく取得できませんでした。

todoList: Array(3) 0: "0" 1: "dscsd" 2: "1" 3: "dscsd"
jun68ykt👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは。

この回答では、削除の仕様を、以下の手順(1),(2)のようなものと解釈しました。

(1) foo, bar, baz, foo, bar, baz を順に追加する。以下のように表示される。

  • foo
  • bar
  • baz
  • foo
  • bar
  • baz

(2) その後、入力欄に bar と入力して [削除] をクリックすると、以下のように表示される。

  • foo
  • baz
  • foo
  • baz

すなわち、入力されたテキストに完全一致する todoアイテムのすべてをリストから削除するものとします。

削除の仕様が上記のようなものであることを前提として、コードの修正は以下のようにすればよいです。

(1) components/Todo

this.statetodo がありますが、削除ボタンをクリックされたときに this.props.delTodo に渡す引数も、 this.state.todo を使うようにします。

修正前:

JSX

1<button onClick={() => this.props.delTodo(this.state.deltodo)}>削除</button>

修正後:

JSX

1<button onClick={() => this.props.delTodo(this.state.todo)}>削除</button>

(2) actions/Todo

上記の (1) に合わせて、アクションクリエータdelTodoで返されるアクションのpayload に含まれるプロパティも修正しておきます。

修正前:

JSX

1export const delTodo = (deltodo) => { 2 return { 3 type: 'DEL_TODO', 4 payload: { deltodo: deltodo } 5 }; 6 }

修正後:

JSX

1export const delTodo = (todo) => { 2 return { 3 type: 'DEL_TODO', 4 payload: { todo } 5 }; 6 }

(3) containers/Todo

(2)と同様に、deltodotodo に修正します。

修正前:

javascript

1delTodo: (deltodo) => dispatch(actions.delTodo(deltodo)),

修正後:

javascript

1delTodo: (todo) => dispatch(actions.delTodo(todo)),

(4) reducers/Todo

削除後の state.todoList を作成する部分を以下のように修正します。

修正前:

javascript

1todoList: state.todoList.concat([action.payload.todo])

修正後:

javascript

1todoList: state.todoList.filter(todo => todo !== action.payload.todo)

動作確認用のコード

ご質問に挙げられているコードに対して上記の修正を加えていったものを、以下のレポジトリ

に上げておきましたので、お手元に git clone するなりして動作確認してみてください。アプリのひな形をcreate-react-appで作っているので、 yarn install , yarn start で動きます。初回のコミットでは、JSのコードはご質問に挙げられているものをそのままコピペしたものを使って、index.jsApp.jsはこちらで適宜作成しました。

もし削除の要件が、冒頭に書いたようなものではない場合は、<input>で入力された文字列から、どのように削除されるアイテムが指定されるのか、コメントからお知らせください。

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

追記

コメントに回答します。

まず初めに、components/Todo.js の以下の部分

JSX

1// StoreのTodoからリストを生成 2const list = this.props.todo.todoList.map((todo, index) => <li key={index}>{todo}</li>)

<li>key として配列のインデクスである index を渡していますが、これは実は推奨されないkey の指定方法です。 Reactのドキュメントの Lists and Keys の下の方に、

JSX

1const todoItems = todos.map((todo, index) => 2 // Only do this if items have no stable IDs 3 <li key={index}> 4 {todo.text} 5 </li> 6);

というコード例に対して

We don’t recommend using indexes for keys if the order of items may change. This can negatively impact performance and may cause issues with component state.

と書かれています。将来、ご質問上げられているコードの todoList も、要素の順序を入れ替える機能を追加したくなるかもしれません。なので、まず todoList を単純な文字列の配列ではなく、以下のような形式のオブジェクトの配列にします。

javascript

1{ 2 id: 10, /* 1ずつ増える整数 */ 3 todo: "コードを書く", /* 文字列 */ 4}

このように、todoListの要素を拡張したのち、

  • IDを特定して、そのIDを持つ要素を配列から削除するアクションとリデューサー内の処理の追加
  • 適宜、各ToDoアイテムごとの1件削除を行うUIを追加

という修正を行います。

さきほど挙げたレポジトリでは、順に、以下の3点のコミットでこれらを行いました。(cloneしたのであれば pull してください)

以下は、現時点のものを実行して、foo, bar, baz とアイテムを追加していったときの表示です。

イメージ説明

ちなみに、 id を 9001 始まりにしているのは特に意味はありませんが、配列のインデクスではない ことを明確にするために 0 始まりではない数字にしてみたという意図です。

上記の状態から bar の左側にある削除ボタンをクリックすると、リストから bar が削除され、以下のようになります。

イメージ説明

以上です。何か不明な点あれば、またコメントください。

投稿2019/05/05 04:45

編集2019/05/05 09:19
jun68ykt

総合スコア9058

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

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

sakusaka

2019/05/05 07:40

jun68ykt さん。こんにちは。 回答ありがとうございます! 文字列でのマッチはうまく動けました! 余分なコードが記載されており、申し訳ないです。 IDが合致した場合に削除するような動きをしたいと思っています。 <li key=1>foo</li> <li key=2>fooo</li> <li key=3>foooo</li> <li key=4>foooo</li> <li key=5>fooooo</li> <li key=6>foooooo</li> <li key=7>fooooooo</li> こうゆうリストがあった場合、 ①Keyをうまくカウントアップさせて表示させる方法 ②Key番号にマッチしたものだけを削除する方法 の2点を実現させることができず、教えていただけると嬉しいです。 お手数おかけして申し訳ないですが、 再度、ご回答いただけると幸いです。 どうぞよろしくお願いいたします。
jun68ykt

2019/05/05 09:20

こんにちは > 文字列でのマッチはうまく動けました! とのことでよかったです! ①②について回答のほうに追記し、対応する修正を、GitHubのほうにコミットしたのでご確認ください。
sakusaka

2019/05/05 10:08

ありがとうございます! コード確認させていただきました。 いただいたコードを参考にしつつ、自分のコードに反映を していたのですが、やはりうまくできず、 IDをカウントアップして、stateに追加するところまではできたのですが、 やはり、componentsにて、liタグを生成するところで、IDがHTMLに描写されないようです。。。 もしよろしければコードを見ていただけますと幸いです。 https://github.com/sakusaka/react-redux-todo.git どうぞよろしくお願いいたします。
jun68ykt

2019/05/05 11:12

コードを拝読しました。 現状に対して、以下のコミット https://git.io/fjnKt のような修正をすると、私のレポジトリの現状とほぼ同じものになります。 一応、上記のコミットを以下ににてPRしたので、問題なさそうであれば、マージして頂ければと思います。(当方のローカルで動作確認はしています。) https://github.com/sakusaka/react-redux-todo/pull/4 もちろんマージしないで、参考にするだけでPRはクローズでもけっこうです。 もとのコードであまりよろしくない点は、id を導入するのはよいのですが、ADD_TODOするごとに、 [action.payload.id, action.payload.todo] をconcatしているところかなと思います。todoList を、 { id: 100, todo: "hoge" } というオブジェクトを要素とする配列にすれば、すっきり出来ます。
jun68ykt

2019/05/05 12:45

feature/dev201903 ブランチの内容を見ました。 まだ、 ・todoReducerに case 'DEL_BY_ID' が無い のと、 ・DEL_TODOによる削除ができない のは、作業途中だからだと思うので、それは置いておくとしまして、確認ですが > IDがHTMLに描写されないです。。。 の疑問は、言い換えると、 components/Todoの中で、 <li key={e.id}> と書いているのに、ブラウザに展開されたHTMLには、この key 属性が <li> に入ってこないのはどうして? ということでしょうか? とすると、この疑問に対する回答としては、key は React が要素のレンダリングを効率的に行うために使うprop で、HTMLに展開されたときに、 key という属性として展開されるものではないです。 なので、id を見た目で確認できるよう表示させるには、keyとは別のところにも書く必要があります。たとえば <li key={e.id}> {e.todo} </li> としているところを、 <li key={e.id}> {e.todo}/{e.id} </li> のようにしておくと、todo が "hoge" で idが 1001 なら、対応する<li>は ・hoge/1001 と表示されます。
jun68ykt

2019/05/05 12:53

もしくは、見た目上では表示させたくないが、 li の何らかの属性値にしておきたいのであれば、data- 属性を使って、 <li key={e.id} data-id={e.id}> {e.todo} </li> としておけば、HTMLに展開されたときには <li data-id="1001">hoge</li> のようになります。
sakusaka

2019/05/07 15:51

おおおお!ありがとうございます!!!!! 表示できました。そういうことなんですね。 全く初歩的な質問に長らくお付き合いいただき、本当にありがとうございます。 そして、最後ご確認遅くなり申し訳ありません。。。 本当にありがとうございました!!
jun68ykt

2019/05/08 05:58

どういたしまして! 解決されたようでよかったです ???? ちなみに、質問の対象になるコードをきちんと用意してGitHub に上げておいたのは、とてもよいと思いました。(ので、質問の評価を+1)
sakusaka

2019/05/08 15:59

ありがとうございます! 他の質問するときも気をつけますね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問