実現したいこと
現在、以下のようなJavaScriptコードをReactを使って書いています。下に示しているのは2つのReactコンポーネントSideBar
とPaperFolder
で、SideBar
の子要素がPaperFolder
という関係にあります。PaperFolder
はMaterial-UIの<List>
を使って書いており、それをSideBar
が持つstateのfolder
という配列に入れて表示します。
今、私が実現したいと思っている機能は、PaperFolder
要素がクリック(選択)されたときにその要素の背景色を変え、以前に選択されていた要素がある場合には背景色をもとに戻すという機能です。何番目の要素が選択されているかは親要素のselectedIdx
で持ちます。このstateはhandleSelectedIdx
というメソッドを子要素(PaperFolder)内のselect
メソッドから呼び出すことによって変更します。ここまでは自力で実装することができたのですが、ある要素をクリックしたときにすでに選択状態になっている要素があったときに選択状態にある要素の背景色をもとに戻すという機能が実装できません。親要素で現在選択している要素のインデックスをもっているので(selectedIdx
)、配列folder
のselectedIdx
番目のPaperFolder
要素のselected
要素を変更すれば良いのだろうということはわかるのですが、これはどのようにしたら書くことができますでしょうか?
javascript
1class SideBar extends React.Component { 2 constructor(props) { 3 super(props); 4 5 this.state = { 6 isOpen: true, 7 numFolders: 0, 8 folders: [], 9 selectedIdx: null, 10 }; 11 12 this.handleDrawer = this.handleDrawer.bind(this); 13 this.createFolder = this.createFolder.bind(this); 14 } 15 16 handleDrawer() { 17 this.setState({isOpen: !this.state.isOpen}); 18 } 19 20 handleSelectedIdx(message) { 21 this.setState({selectedIdx: message.selectedIdx}); 22 } 23 24 createFolder() { 25 this.setState({ 26 folders: this.state.folders.concat( 27 <PaperFolder 28 key={this.state.numFolders} 29 index={this.state.numFolders} 30 deleteFunc={this.deleteFolder.bind(this)} 31 callback={this.handleSelectedIdx} 32 /> 33 ) 34 }); 35 36 this.setState({ numFolders: this.state.numFolders + 1 }); 37 } 38 39 render() { 40 const { classes } = this.props; 41 42 return ( 43 <Drawer 44 variant="permanent" 45 open={this.state.isOpen} 46 > 47 <div className={classes.allFolders}> 48 { this.state.folders } 49 </div> 50 </Drawer> 51 ) 52 } 53}
javascript
1class PaperFolder extends React.Component { 2 constructor(props) { 3 super(props); 4 5 this.state = { 6 selected: false, 7 } 8 9 this.handleListClick = this.handleListClick(this); 10 this.select = this.select.bind(this); 11 } 12 13 handleListClick() { 14 this.setState({selected: !this.state.selected}); 15 } 16 17 select() { 18 this.setState({selected: !this.state.selected}); 19 this.props.callback({'selectedIdx': this.props.index}); 20 } 21 22 render() { 23 const { classes } = this.props; 24 const folderStyle = clsx({ 25 [classes.folder]: true, 26 [classes.selected]: this.state.selected 27 }); 28 29 // TODO: move <List> out of PaperFolder component 30 return ( 31 <List className={classes.folder} onClick={this.select}> 32 <ListItem 33 className={folderStyle} 34 onClick={this.handleListClick} 35 > 36 </ListItem> 37 </List> 38 ) 39 } 40}
追記
親要素からpropsとして渡して制御するように変更してみました。親要素に新たに各PaperFolder要素が選択されているかされていないかを知るための配列(folderSelectedList
)を導入してこれをpropsとして子要素に渡すようにしてみたのですがうまく動作しません。どこがおかしいのでしょう?
javascript
1class SideBar extends React.Component { 2 constructor(props) { 3 super(props); 4 5 this.state = { 6 isOpen: true, 7 numFolders: 0, 8 folders: [], 9 folderSelectedList: [], 10 selectedIdx: null, // store the index of folder selected or null 11 }; 12 13 this.handleDrawer = this.handleDrawer.bind(this); 14 this.createFolder = this.createFolder.bind(this); 15 this.handleSelectedIdx = this.handleSelectedIdx.bind(this); 16 } 17 handleSelectedIdx(message) { 18 var folderSelectedList = this.state.folderSelectedList.slice(); 19 if (this.state.selectedIdx !== null) { 20 folderSelectedList[this.state.selectedIdx] = false; 21 } 22 this.setState({selectedIdx: message.selectedIdx}); 23 folderSelectedList[this.state.selectedIdx] = true; 24 this.setState({folderSelectedList: folderSelectedList}); 25 } 26 27 createFolder() { 28 this.setState({ 29 folderSelectedList: this.state.folderSelectedList.concat(false), 30 folders: this.state.folders.concat( 31 <PaperFolder 32 key={this.state.numFolders} 33 index={this.state.numFolders} 34 isSelected={this.state.folderSelectedList[this.state.numFolders]} 35 deleteFunc={this.deleteFolder.bind(this)} 36 callback={this.handleSelectedIdx} 37 /> 38 ) 39 }); 40 41 this.setState({ numFolders: this.state.numFolders + 1 }); 42 } 43 // ... 44}
javascript
1class PaperFolder extends React.Component { 2 constructor(props) { 3 super(props); 4 5 this.state = { 6 name: "Untitled", 7 } 8 9 this.handleClose = this.handleClose.bind(this); 10 this.select = this.select.bind(this); 11 } 12 13 select() { 14 // this.setState({selected: !this.state.selected}); 15 this.props.callback({'selectedIdx': this.props.index}) 16 } 17 18 render() { 19 const { classes } = this.props; 20 const folderStyle = clsx({ 21 [classes.folder]: true, 22 [classes.selected]: this.props.isSelected 23 }); 24 25 // TODO: move <List> out of PaperFolder component 26 return ( 27 <List className={classes.folder} onClick={this.select}> 28 <ListItem 29 className={folderStyle} 30 onClick={this.handleListClick} 31 > 32 </ListItem> 33 </List> 34 ) 35 } 36}
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/12/07 05:34