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

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

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

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

React.js

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

Q&A

解決済

1回答

3640閲覧

React: 1. ラジオボタンが選択されない 2. Stateが2回目のクリック以降正常に動かない

vankick

総合スコア22

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

React.js

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

0グッド

0クリップ

投稿2019/04/27 02:07

Reactで、フィルター機能を作成しています。
現在、2つの大きな問題があります。

1. ラジオボタンが選択できません。クリックして反応させることはできるのですが、アクティブにならないのです。初期状態のstateをfalseにし、selectしたらtrueになるように設定たらいいのではと思ったのですが、それも上手く動きません。

2. JSONデータを、ラジオボタンのvalueに応じてフィルターしようとしています。let filteredItemを作成し、その中に、大元のJSONデータを、ラジオボタンのvalueでフィルターし、そのデータをpropsとして通そうとしています。
しかし、1回目のクリックでは上手く動くのですが、2回目に別のボタンをクリックすると、filteredItem は空になってしまいます(何の値も入っていない)。どうしたら、フィルター済みのJSONデータをstateに入れ、それをpropsとしてItemコンポーネントに渡すことが出来るのでしょうか。

よろしくお願いします。

import fashion from '../data/fashion.json'; class App extends React.Component { state = { products: fashion } updateItem = (filter) => { this.setState({ products: fashion}) let filteredItem = this.state.products.slice(); let products = filteredItem.filter(item => { if (item.category === filter || item.size === filter) { return true; } }); this.setState({ products: products }) console.log(products); } render() { return ( <div className="wrapper"> <div className="sidebar"> <SideBar onClick = {this.updateItem} items = {this.state.products} /> </div> <main> <Item items = {this.state.products} /> </main> </div> ); } }
export default App; class SideBar extends React.Component { constructor(props) { super(props); this.state = { checked: false } } getValue = (event) => { // console.log("Get value", event.target.value); // Trigers updateItem() on App Component this.props.onClick(event.target.value); } toggleChecked = () => { if(this.state.checked===false) { this.setState({ checked: !this.state.checked }); console.log("toggleChecked", this.state.checked); } } render() { return ( <div> <ul className="category_list"> <li> <input type="radio" value="shirt" checked={this.toggleChecked} onChange={(e) => this.getValue(e)} />Shirts </li> <li> <input type="radio" value="jacket" checked={this.toggleChecked} onChange={(e) => this.getValue(e)} />Jackets </li> <li> <input type="radio" value="skirt" checked={this.toggleChecked} onChange={(e) => this.getValue(e)} />Skirts </li> <li> <input type="radio" value="pants" checked={this.toggleChecked} onChange={(e) => this.getValue(e)} />Pants </li> </ul> <ul> <li> <input type="radio" value="S" checked={this.toggleChecked} onChange={(e) => this.getValue(e)} />S </li> <li> <input type="radio" value="M" checked={this.toggleChecked} onChange={(e) => this.getValue(e)} />M </li> <li> <input type="radio" value="L" checked={this.toggleChecked} onChange={(e) => this.getValue(e)} />L </li> </ul> </div> ); } }
Item.js const Item = (props) => { const renderedList = props.items.map((item) => { return ( <li key={item.id}> <div className="image_container"><img src={item.image} alt={item.name} /></div> <p className="product_name">{item.name}</p> <p className="price">{item.price}</p> <p>Size: {item.size}</p> <p>Category: {item.category}</p> </li> ) }); return <ul className="products">{renderedList}</ul> }
[ { "id": "1", "name": "Black Shirt", "price": "$4.99", "image": "201904041432_1.jpg", "size": "S", "category": "shirt" }, { "id": "2", "name": "Pink Medium Shirt", "price": "$6.99", "image": "201904041432_1.jpg", "size": "M", "category": "shirt" }, { "id": "3", "name": "Red Shirt", "price": "$3.49", "image": "201904190794_1.jpg", "size": "L", "category": "shirt" }, { "id": "4", "name": "Tight Skirt", "price": "$12.99", "image": "401902170012_1.jpg", "size": "S", "category": "skirt" }, { "id": "5", "name": "Short Skirt", "price": "$14.99", "image": "901904190003_1.jpg", "size": "M", "category": "skirt" }, { "id": "6", "name": "Winter Skirt", "price": "$10.99", "image": "401902170126_1.jpg", "size": "L", "category": "skirt" }, { "id": "7", "name": "Black Jacket", "price": "$44.99", "image": "201902181237_1.jpg", "size": "S", "category": "jacket" }, { "id": "8", "name": "Denim Jacket", "price": "$56.99", "image": "042-901811090003_1.jpg", "size": "M", "category": "jacket" }, { "id": "9", "name": "Rider's Jacket", "price": "$84.99", "image": "201902041846_1.jpg", "size": "L", "category": "jacket" }, { "id": "10", "name": "Blue Medium Shirt", "price": "$6.99", "image": "901904240035_1.jpg", "size": "M", "category": "pants" } ]

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは

ざっと見たところ、ご質問の

  • **1.**については、Reactを使って、(ラジオボタンに限らず) <input> などの入力要素から発生したイベントから、入力された値を取得し、それを適切なコンポーネントの state に反映して、再度、入力要素の表示状態に反映させるという一連の流れのご理解がまだ少し曖昧なのかなという印象です。

      

  • 次に、**2.**については、

フィルター済みのJSONデータをstateに入れ、

という着想があまりよろしくないかなという気がしました。
具体的には、Appがstate に持つべき値は以下の2つで事足ります。

  • カテゴリーのフィルタとして選ばれている値
  • サイズのフィルタとして選ばれている値

上記の考えでリファクタしたコードが以下です。(フィルタのクリアやスタイルを適宜追加、修正しています)

App.js

JSX

1import React from 'react' 2import SideBar from './SideBar'; 3import Item from './Item'; 4import FASHION_DATA from '../data/fashion.json'; 5import './App.css'; 6 7class App extends React.Component { 8 9 state = { 10 category: "", 11 size: "", 12 } 13 14 filterChange = (e) => { 15 this.setState({ 16 [e.target.name]: e.target.value, 17 }); 18 } 19 20 filterClear = () => { 21 this.setState({ 22 category: "", 23 size: "", 24 }) 25 } 26 27 render() { 28 const { category, size } = this.state; 29 const items = FASHION_DATA.filter(item => 30 [item.category, ""].includes(category) && 31 [item.size, ""].includes(size) 32 ); 33 34 return ( 35 <div className="wrapper"> 36 <div className="sidebar"> 37 <SideBar 38 filter={this.state} 39 onChange={this.filterChange} 40 onClear={this.filterClear} 41 /> 42 </div> 43 44 <main> 45 <Item items={items} /> 46 </main> 47 </div> 48 ); 49 } 50} 51 52export default App; 53

SideBar.js

JSX

1import React from 'react' 2 3const FILTER_VALUES = [ 4 { name: 'category', values: ['shirt', 'jacket', 'skirt', 'pants'] }, 5 { name: 'size', values: ['S', 'M', 'L'] } 6]; 7 8class SideBar extends React.Component { 9 render() { 10 const { filter, onChange, onClear } = this.props; 11 12 return ( 13 <div> 14 { 15 FILTER_VALUES.map(({name, values}) => 16 <ul 17 className={`${name}_list`} 18 key={name} 19 > 20 { 21 values.map(v => 22 <li key={v}> 23 <input 24 name={name} 25 type="radio" 26 value={v} 27 checked={filter[name] === v} 28 onChange={onChange} 29 /> 30 <span className='capitalize'>{v}</span> 31 </li> 32 ) 33 } 34 </ul> 35 ) 36 } 37 <button onClick={onClear}>フィルタをクリア</button> 38 </div> 39 ); 40 } 41} 42 43export default SideBar; 44

Item.js

JSX

1import React from 'react' 2 3const Item = (props) => { 4 const { items } = props; 5 6 const renderedList = items 7 .map(item => { 8 return ( 9 <li key={item.id}> 10 <div className="image_container"><img src={item.image} alt={item.name} /></div> 11 <p className="product_name">{item.name}</p> 12 <p className="price">{item.price}</p> 13 <p>Size: {item.size}</p> 14 <p>Category: {item.category}</p> 15 </li> 16 ) 17 }); 18 19 return <ul className="products">{renderedList}</ul> 20}; 21 22export default Item;

App.css

css

1.sidebar ul { 2 list-style: none; 3 border: 1px solid #ccc; 4} 5 6main ul { 7 list-style: none; 8} 9 10main li { 11 border: 1px solid #ccc; 12 margin-bottom: 5px; 13} 14 15.capitalize { 16 text-transform: capitalize; 17}

上記のコードを以下にpushしていますので、お手元に clone するなどして、動かしてみてください。

なお上記のレポジトリの最初のコミット では、コンポーネント(App, SideBar, Item) のコードはご質問に挙げられているものをほぼそのままコミットしており、その後、何度かのコミットを経て上記のコードになっています。

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

追記

SideBarItemと同様に state を持たないので、 Functional Component にしました。

投稿2019/04/27 05:14

編集2019/04/27 05:36
jun68ykt

総合スコア9058

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

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

vankick

2019/04/27 06:58

非常にご丁寧に解説していただき、ありがとうございます! 正直まだ修正していただいたコードの意味は完璧には理解できていない部分もあるのですが、これからじっくり見させていただきたいと思います。
jun68ykt

2019/04/27 07:01

どういたしまして! 回答のコードについて何か不明点あれば、またコメント頂ければと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問