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

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

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

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

React.js

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

Q&A

解決済

3回答

590閲覧

React+Reduxで、Reduxと紐付いたComponentを複数箇所で使う場合の書き方がわからない

masaya_ohashi

総合スコア9206

Redux

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

React.js

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

1グッド

0クリップ

投稿2018/03/23 05:44

編集2018/03/23 06:33

前提・実現したいこと

例えばclickerという名前のReducerと、store上のclickerのデータを参照するClickerというComponentがあるとします。
このClickerというComponentを複数箇所で使う場合、storeの中にはclickerという名前のものが1つしかないのですが、それぞれの使用箇所で独立した状態で管理するにはどのように書くのが一般的なのでしょうか?そもそもこのように汎用的なComponentの内部情報をReduxで管理するのが間違いなのでしょうか?

発生している問題・エラーメッセージ

別々のデータをstoreで扱いたいが、共通になってしまう。

該当のソースコード

JavaScript

1// actions/clicker.js 2function clickerClick() { 3 return {type:'clicker.click'}; 4} 5const ClickerActions = { 6 clickerClick 7}; 8export default ClickerActions;

JavaScript

1// reducers/clicker.js 2const initialState = {value:0} 3function clicker(state=initialState, action) { 4 switch(action.type) { 5 case 'clicker.click': 6 let ret = Object.assign({}, state); 7 ret.value++; 8 return ret; 9 } 10 return state; 11}

JavaScript

1// reducers/main.js 2const mainApp = combineReducers({ 3 main, 4 clicker, // ←reducers/clicker.js 5}); 6 7export default mainApp;

JavaScript

1// components/Clicker.js 2class Clicker extends Component { 3 render() { 4 return <div onClick={e=>this.props.actions.clickerClick()}>{this.props.clicker.value}</div>; 5 } 6} 7function mapStateToProps(state) { 8 return {clicker:state.clicker}; 9} 10function mapDispatchToProps(dispatch) { 11 return { 12 actions: bindActionCreators(Object.assign({}, ClickerActions), dispatch) 13 }; 14} 15 16export default connect(mapStateToProps, mapDispatchToProps)(Clicker);

この状態で<Clicker>を複数箇所に使用したとき、storeにはclickerという入れ物は1つしかないので相互に影響してしまうため、独立したデータで持ちたい。

JavaScript

1class Hoge extends Component { 2 render() { 3 return ( 4 <div> 5 <div> 6 <h1>Clicker 1</h1> 7 <Clicker/> 8 </div> 9 <div> 10 <h1>Clicker 2</h1> 11 <Clicker/> 12 </div> 13 <div>; 14 } 15}

このように複数箇所で使用した場合、Clicker 1とClicker 2で独立したデータを持てるようにしたいです。Clicker 1で発生したactionはClicker 1にのみ影響を与えるようにしたいです。いまのままだとClicker 1が書き換わるとClicker 2も同時に書き換わってしまいます。そもそもreducerがclickerという共通のものを使ってしまう以上、store内に保存されるデータを別々にすることは出来ないのでしょうか?

試したこと

いろいろ調べようとしているのですが、どういう用語で調べたものかわからず、なかなか情報に行き当たりません…

【追記】
この方も同じような悩みを抱えているようです。しかしスマートな解決法は見つかっていないようです…
https://qiita.com/derui@github/items/8272c5cb7eb7fc3ecd67

補足情報(FW/ツールのバージョンなど)

package.json一部抜粋

"react": "^16.2.0", "react-redux": "^5.0.7", "redux": "^3.7.2",
HayatoKamono👍を押しています

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

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

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

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

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

HayatoKamono

2018/03/23 05:55

何をしたいのか、何に困っているのか、状況がよく伝わってこないので、もう少し詳細な内容を追記頂けますでしょうか?また、コンポーネントAとBを作って、それらを使っているコードを追記頂けますでしょうか?
guest

回答3

0

質問者様がおっしゃっている通り、 同じreducerを利用している以上、同じstateを更新することしか出来ません。
reducerのstate内で分けて持つようなことも出来ますが、管理が煩雑になるためあまりおすすめ出来ません。

そもそも、reduxと紐づけたreact componentを複数箇所で使っている以上、同じデータを更新するのが期待される動作かと思いますので、別のデータを管理したいのであればcomponentを共通で使用すること自体設計が間違えているように思います。

Componentを共通で利用したい理由がデザインの共有等にあるのであれば、HoCを用いてデザインとClickイベントのみを持ったComponentと、Clickされたときの処理を定義するComponentに分けて実装するのがよいかと思います;。
HoCについては以下が参考になるかと。
https://postd.cc/react-higher-order-components-in-depth/
https://qiita.com/numanomanu/items/2b66d8b2887d44f857dc

投稿2018/03/23 06:37

k.tada

総合スコア1679

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

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

0

ベストアンサー

初期の質問文から最終的な質問内容にだいぶ変化し、質問もシンプルなものになっていたため、元の回答を削除し、現在の質問文をベースにした回答に変更 - 2018/03/27

#1

class Hoge extends Component { render() { return ( <div> <div> <h1>Clicker 1</h1> <Clicker/> </div> <div> <h1>Clicker 2</h1> <Clicker/> </div> <div>; } }

↑この場合であれば、Clickerコンポーネントをstoreに繋げるのではなく、Hogeコンポーネントをstoreに繋げて、Clickerが必要とするアクションやデータをpropsで渡してあげるのが一般的なやり方かと思います。

#2

// reducers/clicker.js const initialState = {value:0}

// reducers/clicker.js const initialState = [ { id:1, value:0 }, { id:2, value:0 } ];

Hogeコンポーネントでは、storeから参照できる上記のような配列をmap overしてclickerコンポーネントをレンダー。

#3

// actions/clicker.js function clickerClick() { return {type:'clicker.click'}; }

function clickerClick(id) { return { type:'clicker.click', payload: id }; }

action creatorの引数でclickerのidを渡せるようにして、reducerがどのclicker idのデータかを判別できるようにし、クリックされたidのカウントをreducerでインクリメントして、新しいstateを返す。

投稿2018/03/23 06:10

編集2018/03/27 05:22
HayatoKamono

総合スコア2415

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

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

masaya_ohashi

2018/03/23 06:22

もっと実際の使用シーンに沿ったクラス名に変えてみました。
masaya_ohashi

2018/03/23 06:26

回答のほう読ませていただきましたが、やはりstate内で各使用箇所でidを振ってやるしかないのでしょうか…その方法は思いついていたのですが、あまりにもスマートでないというか…こういう汎用的なものはReduxよりReactのstateに任せるべきですかね?
HayatoKamono

2018/03/23 06:32

すみません。名前がHogeやClicker1,2になっても尚、具体的なシーンがわからず何にしたいのか分かってません。とりあえず、抽象的な回答を1つ追加すると、「 function clickerClick() { return {type:'clicker.click'}; } 」のclickerClickの引数に例えば、idなどの値を渡して、action objectにtypeだけではなく、引数に渡ってきた値も加えて、reducerに投げてあげれば、reducer側でなんか出来るのだと思います。(抽象的な回答にまたもやなりますが。。)
HayatoKamono

2018/03/23 06:33

> こういう汎用的なものはReduxよりReactのstateに任せるべきですかね? Reduxを使うのであれば、Reactで持たせるstateはUIに関するstateにしてビューに徹させた方が良いかと思います。
masaya_ohashi

2018/03/23 06:35

私と同じ問題を抱えた人を見つけたので参考としてURLを貼りました。 この人は「エディタ」を作ろうとして、同一ページ上に複数のエディタを並べたときに、それぞれ独立したデータを持たせたいようです。
HayatoKamono

2018/03/23 06:58 編集

リンク先拝見しましたが、リンク先の方とmasaya_ohashiさんが同じ問題を抱えているのかどうかの判断は、自分にはこの質問文のコードからは付きませんでした。 また、リンク先の2年ほど前の記事ですが、なぜ「全てのエディタコンポーネントで別のStoreを持つ」ことをしたいのかの理由が書かれていないようでしたし、その少し前に書かれていた「それを一つのStoreの中に配置しようとした時に、 エディタ側は渡されるStoreの構造に依存したくない」という部分に関しては同記事前半で述べられているpresentaional component とcontainer componentの分離でそれこそ解決することなのではと思いましたし、リンク先記事についてもいまいちよく分かりませんでした。 とりあえず、私からは以上と致します。
masaya_ohashi

2018/03/27 07:13

これはわかりやすい回答ですね! なるほど親にひも付けをさせるという発想はなかったです。これなら様々な場所でidさえ割り当てればデータを別にできそうです。
HayatoKamono

2018/03/27 07:17

おー、それは良かったです!最初のややこしい質問内容に引きずられていたみたいで、最終的に編集された内容に上手く回答出来てなかったみたいです。
guest

0

https://redux.js.org/recipes/structuring-reducers/reusing-reducer-logic

公式的には

  • reducerで複数の名前で登録する
  • actionのtypeの末尾にIDを付与してdispatchする
  • 該当するreducerが受け取る
  • 各Componentは自身に紐付くstoreのデータを使う

というのが再利用可能reducerの作り方だそうです…1個2個程度ならいいですがたくさんの場所に使う場合、あまりにも不便過ぎます…

拡張パッケージ等でCoolなものがないか、しばらく質問は未解決のままにしておきます。

投稿2018/03/23 06:55

masaya_ohashi

総合スコア9206

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問