teratail header banner
teratail header banner
質問するログイン新規登録

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

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

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

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

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

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

Q&A

解決済

2回答

1577閲覧

Reactで複数のselect要素の値をそれぞれユニークな値にしたい

taku-hu

総合スコア178

JavaScript

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

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

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

0グッド

0クリップ

投稿2021/07/06 18:53

0

0

前提・実現したいこと

お世話になっております。

タイトル通りReactで複数のselect要素の値をそれぞれユニークな値にしたいと思っています。
例えば3つのselect要素があり、それぞれ1~3の数字が選択できるとして、いずれかで1を選択した場合は他の2つでは1が選択できなくなる、という仕様にしたいです。

一応自分なりに実装はしてみたのですが、なぜか画面上でselect要素が更新されずおかしな動きになっています。

codesandboxのサンプル

該当のソースコード

tsx

1import { useState, ChangeEvent } from 'react' 2 3type RankData = { 4 name: string 5 rank?: string 6} 7const initialData = [{ name: '佐藤' }, { name: '田中' }, { name: '鈴木' }, { name: '高橋' }] 8const ranks = ['1位', '2位', '3位', '4位'] 9 10export const App = () => { 11 const [rankData, setRankData] = useState<RankData[]>(initialData) 12 const unselectedRanks = ranks.filter((rank) => { 13 const usedRanks = rankData.map(({ rank: usedRank }) => usedRank) 14 return !usedRanks.includes(rank) 15 }) 16 const updateRankData = (e: ChangeEvent<HTMLSelectElement>, targetIndex: number) => { 17 setRankData((preRankData) => 18 preRankData.map((preData, index) => { 19 const { name } = preRankData[targetIndex] 20 const rank = e.target.value 21 return index === targetIndex ? { name, rank } : preData 22 }) 23 ) 24 } 25 26 return ( 27 <div id="app"> 28 {rankData.map(({ name, rank }, index) => ( 29 <div key={name}> 30 <p>{name}</p> 31 <select onChange={(e) => updateRankData(e, index)} value={rank}> 32 <option>--順位を選択--</option> 33 {unselectedRanks.map((unselectedRank) => ( 34 <option key={unselectedRank} value={unselectedRank}> 35 {unselectedRank} 36 </option> 37 ))} 38 </select> 39 </div> 40 ))} 41 </div> 42 ) 43}

試したこと

上記の通り、unselectedRanksというrankData内で使われていない値を保持する配列を作成して、それをループさせてoptionを作成しました。
今の自分では、正直どこが間違っているのか分からないので、よろしければみなさん力をお貸しください。

codesandboxのサンプル

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

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

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

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

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

guest

回答2

0

ベストアンサー

例えば佐藤さんが 1 位の場合、佐藤さんの select 要素には '1位' も表示する必要があるので、次のように unselectedRanks を関数にすれば良いのでは。
また、順位を選択済みの人を「--順位を選択--」に戻した場合に rank: '--順位を選択--' という情報が入ってしまうので、その場合の value は '' にするとか…。

diff

1 export const App = () => { 2 const [rankData, setRankData] = useState<RankData[]>(initialData) 3- const unselectedRanks = ranks.filter((rank) => { 4- const usedRanks = rankData.map(({ rank: usedRank }) => usedRank) 5- return !usedRanks.includes(rank) 6+ const unselectedRanks = (name: string) => ranks.filter((rank) => { 7+ return rankData.every((data) => data.name === name || data.rank !== rank); 8 }) 9 10 // 略 11 12 <select onChange={(e) => updateRankData(e, index)} value={rank}> 13- <option>--順位を選択--</option> 14- {unselectedRanks.map((unselectedRank) => ( 15+ <option value=''>--順位を選択--</option> 16+ {unselectedRanks(name).map((unselectedRank) => ( 17 <option key={unselectedRank} value={unselectedRank}>

投稿2021/07/06 22:27

hoshi-takanori

総合スコア7903

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

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

taku-hu

2021/07/08 03:09

全て共通のunselectedRanksを使っていると自身で選んだ選択肢も消えてしまう、という事に全然気づけませんでした... あとそれを踏まえてもeveryで一発で出す実装は浮かばなかったので勉強になりました。 ご回答ありがとうございました。
guest

0

今の自分では、正直どこが間違っているのか分からないので、

全部のセレクトボックスに対して同じunselectedRanksを使うのが妥当ではありません。「1位」を選んだ箇所では、1位をリストに残しておく必要があります。

投稿2021/07/06 22:24

maisumakun

総合スコア146641

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

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

taku-hu

2021/07/08 03:04

言われてみれば自身で選んだ瞬間にその選択肢も消えてしまうので、画面上で選択できていない状態になるのは当然でした... ご回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

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

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

質問する

関連した質問