Reputation: 35
Sorry if the phrasing of my question is unclear. I'm new to React and making an app with three different screens/pages. There should be a footer that follows the state of the payment process thanks to 3 boxes. The box that is being selected should show up in another color (here I've used a solid blue border).
When clicking on another box (box 3 for example), I would like the third box to be selected and the other two boxes to be unselected. In order to achieve this, I've set up a state.active in the child element. If the state is active, then a different style is applied to the element (the blue border).
I have two components, "ProgressBar" being the parent, and "ProgressElement" being the child. Here is what the code looks like :
class ProgressElement extends React.Component {
constructor(props) {
super(props);
this.state = {
selected: false
}
this.handleClick = this.handleClick.bind(this)
}
componentDidMount() {
if (this.props.eleType === "pattern") {
this.setState({selected: true})
}
}
handleClick() {
if (!this.state.selected) {
this.setState({selected: true})
}
if (this.state.selected) {
this.setState({selected: false})
}
}
render() {
let eleNumber = NaN
if (this.props.eleType === "pattern") {
eleNumber = 1;
this.state.selected === true;
}
if (this.props.eleType === "gift") {
eleNumber = 2;
}
if (this.props.eleType === "personal") {
eleNumber = 3;
}
if (this.state.selected) {
return <div className="square-box selected"
onClick={this.handleClick}>{eleNumber}</div>
} else {
return <div className="square-box"
onClick={this.handleClick}>{eleNumber}</div>
}
}
}
class ProgressBar extends React.Component {
render() {
return <div className="d-flex custom-progress-bar">
<ProgressElement eleType="pattern"/>
<ProgressElement eleType="gift"/>
<ProgressElement eleType="personal"/>
</div>
}
}
It's working fine, but my only problem is that I don't know how to make the other boxes unselected. For that, I would need the other sibling elements to be aware of the state of the other ones. I've thought of two ways to do this but have been unable to make one of these work so far :
Could anyone help me with this ? I know this is probably basic stuff but I'm having a hard time with React. Thanks for reading me and thanks in advance.
Upvotes: 1
Views: 741
Reputation: 628
Try and apply this, I did not test the code myself so make sure that you apply the logic to your code (I'm rusted with classes)
class ProgressElement extends React.Component {
render() {
if (this.props.eleType === this.props.selected) {
return <div className="square-box selected"
onClick={this.props.act({selectedValue:""})}>{this.props.eleType}</div>
} else {
return <div className="square-box"
onClick={this.props.act({selectedValue:this.props.eleType})}>{this.props.eleType}</div>
}
}
}
class ProgressBar extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedValue: ""
}
}
updateSelected = (selected) => {
this.setState(selected);
}
render() {
return <div className="d-flex custom-progress-bar">
<ProgressElement eleType="pattern" act={this.updateSelected} selected={this.state.selectedValue}/>
<ProgressElement eleType="gift" act={this.updateSelected} selected={this.state.selectedValue}/>
<ProgressElement eleType="personal" act={this.updateSelected} selected={this.state.selectedValue}/>
</div>
}
}
Upvotes: 1
Reputation: 15530
You need to keep track of currently active child within the parent component and pass it down as a prop:
const { Component } = React,
{ render } = ReactDOM,
rootNode = document.getElementById('root')
class ProgressElement extends React.Component {
handleClick = eleType => this.props.onSetActive(eleType)
render(){
return (
<div
className={this.props.eleType === this.props.activeEleType && 'active'}
onClick={() => this.handleClick(this.props.eleType)}
>
{this.props.eleType}
</div>
)
}
}
class ProgressBar extends React.Component {
state = {activeEleType: null}
onSetActive = activeEleType => this.setState({
activeEleType
})
render() {
return (
<div className="progress-bar">
{
['pattern', 'gift', 'personal'].map(key => (
<ProgressElement
activeEleType={this.state.activeEleType}
eleType={key}
key={key}
onSetActive={this.onSetActive}
/>
))
}
</div>
)
}
}
render (
<ProgressBar />,
rootNode
)
.progress-bar {
display: flex;
}
.progress-bar>div {
width: 100px;
height: 100px;
background: grey;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
margin: 10px;
cursor: pointer;
}
.progress-bar>div.active {
border: 2px solid blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
Upvotes: 2