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

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

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

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

Q&A

解決済

1回答

4088閲覧

ReduxのReducerのリストの更新が上手くいきません

退会済みユーザー

退会済みユーザー

総合スコア0

Redux

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

0グッド

0クリップ

投稿2018/03/25 08:29

編集2018/03/25 11:31

React,Reduxでアプリを作っているのですが、stateのlistが上手く更新できません
先日の質問を参考にして、入れ子のリストを使ったreducerを実装しています。

なにがしたいのか

上述のページで質問したことも踏まえて、
「入れ子リストのstateをreduxを用いて実装し、そこにリストを追加する」です。

実装したいものの概要

まず、2次元配列のような入れ子のリストのstateを用意します。

questionList:[ ['title1','message1'], ['title2','message2'], ['title3','message3'], ['title4','message4'], ['title5','message5'], ]

ユーザーがボタンを押したタイミングでここに新たな[title6,message6]を追加したいのです。

questionList:[ ['title1','message1'], ['title2','message2'], ['title3','message3'], ['title4','message4'], ['title5','message5'], ['title6','message6'], ]

しかし、ここでただ単に追加するだけなのであれば、以下のコードで実現します。
しかし、ここでは
ボタン押す→サーバーに追加→サーバーから全データを取得→描画
としたいので、以下のコードでは問題が起こります。

問題が生じているコード

javascript

1import * as actionTypes from "../actionTypes" 2 3/* 4* InitialState 5===================================*/ 6const initialStateQuestionList = { 7 title: null, 8 message: null, 9} 10 11/* 12* questionListReducer 13===================================*/ 14export const questionListReducer = (state = initialStateQuestionList, action) => { 15 switch (action.type) { 16 /*= QuestionPage =========*/ 17 case actionTypes.SET_QUESTION_TITLE: 18 if (state.id !== action.id) { 19 return state 20 } 21 return Object.assign({}, state, { 22 title: action.title, 23 message: action.message, 24 }) 25 26 default: 27 return state 28 } 29} 30 31/* 32* questionListsReducer 33===================================*/ 34const initialState = { 35 questionList: [], 36} 37 38/* 39* questionListsReducer 40===================================*/ 41export const questionListsReducer = (state = initialState, action) => { 42 switch (action.type) { 43 44 case actionTypes.SET_QUESTION_TITLE: 45 return Object.assign({}, state, { 46 questionList: state.questionList.map(t => 47 questionListReducer(t, action) 48 ) 49 }) 50 51 default: 52 return state 53 } 54} 55 56export default questionListsReducer

どんな問題が起こるか

今初期値としてサーバー内に5つのデータ、仮にそのtitleがa,b,c,d,eという文字列だとすると、

初期値は以下のようになっているとします。

[ ['a','message1'], ['b','message2'], ['c','message3'], ['d','message4'], ['e','message5'], ]

ここで、ボタンを押し、サーバーに1つ新しいデータfを送り、全データを取得すると、

[ ['a','message1'], ['b','message2'], ['c','message3'], ['d','message4'], ['e','message5'], ['a','message1'], ['b','message2'], ['c','message3'], ['d','message4'], ['e','message5'], ['f','message5'], ]

という風に追加されてしまいます。

これを、

[ ['a','message1'], ['b','message2'], ['c','message3'], ['d','message4'], ['e','message5'], ['f','message5'], ]

という風に更新したいです。

よろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

※当初の質問から大きく内容に変更があったため、回答を一旦、全削除しました。

しかし、ここでただ単に追加するだけなのであれば、以下のコードで実現します。

しかし、ここでは
ボタン押す→サーバーに追加→サーバーから全データを取得→描画
としたいので、以下のコードでは問題が起こります。

いえ、関係ないです。

質問を追加するボタンのことや、API、データベースのことは一旦忘れてください。

reducerは現在のstateとactionオブジェクトを引数にとって、新しいstateを返す、または現在のstateをそのまま返す関数にしか過ぎません。

まず、reducer単体で期待する結果を得られるようにコードを書いてください。

例えば、掲載されている内容を元に該当reducerのコードをテストコード付きで書くとしたら以下のようになります。

// questionListsReducer.js

export default function questionListsReducer(state, action) { switch (action.type) { //質問文に記載通りのかたち case "update_all": return { questionList: action.payload }; //新規追加データのみreducerに渡ってきた場合 case "add_questions": return { questionList: [...state.questionList, ...action.payload] }; default: return state; } }

// questionListsReducer.test.js

import questionListsReducer from './questionListsReducer'; describe('questionListsReducer', () => { // ディープコピーは面倒なので、サンプルコードでは配列ではなくオブジェクトに変更します。。。 const initialState = { questionList: [ { title: 'title1', message: 'message1' }, { title: 'title2', message: 'message2' }, { title: 'title3', message: 'message3' }, { title: 'title4', message: 'message4' }, { title: 'title5', message: 'message5' } ] } const expectedResult = { questionList: [ { title: 'title1', message: 'message1' }, { title: 'title2', message: 'message2' }, { title: 'title3', message: 'message3' }, { title: 'title4', message: 'message4' }, { title: 'title5', message: 'message5' }, { title: 'title6', message: 'message6' } ] }; it('should replace an existing questionList with a new questionList', () => { const action = { type: 'update_all', // 質問文に書かれていたように全データが渡ってくるとする payload: [ { title: 'title1', message: 'message1' }, { title: 'title2', message: 'message2' }, { title: 'title3', message: 'message3' }, { title: 'title4', message: 'message4' }, { title: 'title5', message: 'message5' }, { title: 'title6', message: 'message6' } ] } const result = questionListsReducer(initialState, action); expect(result).toEqual(expectedResult); //test passes. }); it('should add new questions to the existing questionList', () => { const action = { type: 'add_questions', // 追加した新規データのみ渡ってくるとする payload: [ { title: 'title6', message: 'message6' } ] } const result = questionListsReducer(initialState, action); expect(result).toEqual(expectedResult); //test passes. }); })

サーバーから全データを取得

新規追加したデータだけAPIサーバーから返してもらうことができるなら、そうした方が良いかと思いますが、全データを取得することが必須なのであれば、単純に上記コードのように、既存のstate内のリストをAPIから取得した全リストに置き換えてしまえば良いだけかと思います。

APIから新規追加したデータのみ返してもらえるならば、reducerのactionにはその新規データのみが渡ってくるので、それを既存のリストに追加してあげれば良いだけの話かと思います。

追記

しかし、ここでただ単に追加するだけなのであれば、以下のコードで実現します。

しかし、ここでは
ボタン押す→サーバーに追加→サーバーから全データを取得→描画
としたいので、以下のコードでは問題が起こります。

いや、「ボタン押す→サーバーに追加→サーバーから全データを取得→描画」に関係なく、
単に追加するだけであっても掲載のコードでは実現しないですよね?

2次元配列のリストがreducerのactionに渡ってくるということなのですから、それが掲載されているreducerのコードの引数になったとして、得たい結果にはならないはずです。また、これが二次元配列ではなく編集前の配列の中にオブジェクトがあるような場合であっても、掲載されているコードでは得たい結果は得られていないはずです。

なので、まずは「ボタン押す→サーバーに追加→サーバーから全データを取得→描画」のことをreducerから切り離して、
reducer単体でしっかりと得たい結果が得られるコードにしましょう。これだけで他にバグがないのであれば得たい結果に自然となるはずです。

その上でも尚、得たい結果に描画の時点でならない場合は、(A)reducerに期待しているデータが渡ってきていない、(B)描画する側でミスってる、のいずれかのバグが更にあるのだと思います。

Reducerのロジックについて全然理解していないのですが、

&

reducerについてよく理解していないので、これが合っているのか間違っているのかもわかりません。

であれば、まずはそこを理解するように努めてから先へ進んだ方が効率も良いのではないでしょうか。

2段飛ばし、3段飛ばしの状態で進んでいても非効率かと思いますし、また、その状態で質問をしても、
的はずれな質問になってしまう可能性が高くなったり、「動くコードに直してくれ」レベルの質問になってしまったり、
回答を得られたとしても、2段飛ばし、3段飛ばしになっている状態に合わせた回答が寄せられたりして、
せっかく得られた回答も理解できずに無駄になってしまったりするのかなと思います。

投稿2018/03/25 09:04

編集2018/03/26 02:51
HayatoKamono

総合スコア2415

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問