はじめに
React + Typescript + MaterialUIでフロントエンドを作成していたときに実現したいことができなかったので参考程度に投稿します。
実現できなかった原因
Chipの×ボタンを押してもSelectのメニューが出てきてしまう
実現したいこと
MaterialUIの公式ドキュメントに書かれていた「Multiple Select(Chip)」でChipの×ボタンからも選択を解除したい!
結論
Chipコンポーネントに以下プロパティを追加
onMouseDown={(event)=>{event.stopPropagation();}}
前提条件
- typescript,React,MaterialUiについてある程度の知識がある。
- create-react-appでアプリケーションが作成済み
npx create-react-app {your_app_name} --template typescript
- material-uiがインストール済み
npm install @material-ui/core
Multiple SelectのChipを動かしてみる
まずは何も考えずコードをすべてコピーしてApp.tsx
に貼り付ける。
次にChip以外のところは邪魔なのでChipに関連するものだけを残す。
そうするとコードは以下のようになります。
importReactfrom'react';import{createStyles,makeStyles,useTheme,Theme}from'@material-ui/core/styles';importInputfrom'@material-ui/core/Input';importInputLabelfrom'@material-ui/core/InputLabel';importMenuItemfrom'@material-ui/core/MenuItem';importFormControlfrom'@material-ui/core/FormControl';importSelectfrom'@material-ui/core/Select';importChipfrom'@material-ui/core/Chip';constuseStyles=makeStyles((theme:Theme)=>createStyles({formControl:{margin:theme.spacing(1),minWidth:120,maxWidth:300,},chips:{display:'flex',flexWrap:'wrap',},chip:{margin:2,},noLabel:{marginTop:theme.spacing(3),},}),);constITEM_HEIGHT=48;constITEM_PADDING_TOP=8;constMenuProps={PaperProps:{style:{maxHeight:ITEM_HEIGHT*4.5+ITEM_PADDING_TOP,width:250,},},};constnames=['Oliver Hansen','Van Henry','April Tucker','Ralph Hubbard','Omar Alexander','Carlos Abbott','Miriam Wagner','Bradley Wilkerson','Virginia Andrews','Kelly Snyder',];functiongetStyles(name:string,personName:string[],theme:Theme){return{fontWeight:personName.indexOf(name)===-1?theme.typography.fontWeightRegular:theme.typography.fontWeightMedium,};}exportdefaultfunctionMultipleSelect(){constclasses=useStyles();consttheme=useTheme();const[personName,setPersonName]=React.useState<string[]>([]);consthandleChange=(event:React.ChangeEvent<{value:unknown}>)=>{setPersonName(event.target.valueasstring[]);};return(<div><FormControlclassName={classes.formControl}><InputLabelid="demo-mutiple-chip-label">Chip</InputLabel><SelectlabelId="demo-mutiple-chip-label"id="demo-mutiple-chip"multiplevalue={personName}onChange={handleChange}input={<Inputid="select-multiple-chip"/>}renderValue={(selected)=>(<divclassName={classes.chips}>{(selectedasstring[]).map((value)=>(<Chipkey={value}label={value}className={classes.chip}/>))}</div>)}MenuProps={MenuProps}>{names.map((name)=>(<MenuItemkey={name}value={name}style={getStyles(name,personName,theme)}>{name}</MenuItem>))}</Select></FormControl></div>);}
そしてこれをnpm start
してhttp://localhost:3000
でみると
よさそう!※拡大してます
Chipの×ボタンを表示する
Chipに×ボタンを表示するにはChipコンポーネントにonDelete
プロパティを追加すればいい。
<Chipkey={value}label={value}className={classes.chip}onDelete={()=>{alert(value)}}/> #ここを追加
今回は×ボタンをがクリックされたことを確認するために、alertでクリックしたChipのラベルを表示するようにした。
そして再度npm start
あれ...?何度押しても×ボタンがクリックできずにSelectのメニューが出てきてしまう。
対処法
Chipコンポーネントに以下プロパティを追加
<Chipkey={value}label={value}className={classes.chip}onDelete={()=>{alert(value)}}onMouseDown={(event)=>{event.stopPropagation()}}#ここを追加/>
今度はきちんとクリックされてアラートが出ていますね。
Chip削除の処理を追加する
先ほど入れたalertの処理をChip削除(personName内の名前を削除)する処理に変える。
新しくchipDelete
という関数を用意する
const chipDelete = (name: string) => {
setPersonName(personName.filter(value => value !== name))
}
そうするとApp.tsx
のfunction MultipleSelect()
は以下のようになる
exportdefaultfunctionMultipleSelect(){constclasses=useStyles();consttheme=useTheme();const[personName,setPersonName]=React.useState<string[]>([]);consthandleChange=(event:React.ChangeEvent<{value:unknown}>)=>{setPersonName(event.target.valueasstring[]);};constchipDelete=(name:string)=>{setPersonName(personName.filter(value=>value!==name))};return(<div><FormControlclassName={classes.formControl}><InputLabelid="demo-mutiple-chip-label">Chip</InputLabel><SelectlabelId="demo-mutiple-chip-label"id="demo-mutiple-chip"multiplevalue={personName}onChange={handleChange}input={<Inputid="select-multiple-chip"/>}renderValue={(selected)=>(<divclassName={classes.chips}>{(selectedasstring[]).map((value)=>(<Chipkey={value}label={value}className={classes.chip}onDelete={(event)=>chipDelete(value)}onMouseDown={(event)=>{event.stopPropagation();}}/>))}</div>)}MenuProps={MenuProps}>{names.map((name)=>(<MenuItemkey={name}value={name}style={getStyles(name,personName,theme)}>{name}</MenuItem>))}</Select></FormControl></div>);}
うまくいった!!!!
終わりに
今思うとこんなにすっとできてしまうなんて。。。
ただ単にコピペするだけではなくてどのような処理が行われていて、どんなオプションのプロパティがあるのかを確認しないといけないですね。