Robkwood
Robkwood

Reputation: 365

React - one event handler to toggle one of multiple similar elements

I'm trying to practice React by rebuilding an agency website. I'm working on a section which has staff images, and clicking one of those images opens the relevant staff bio in a modal. The images and the bios are in separate containing divs.

It feels like I should be able to write one event handler that finds and opens the relevant bio depending on which image is clicked (maybe using something like the data attribute?), but I can't figure out what I'd need to add.

Currently I just have a click handler which toggles a piece of 'active' state. That state is then added as a className to toggle whether the modal is showing. Problem of course being that it doesn't differentiate between bios, so they all show regardless which bio is clicked on.

In case it's useful, here is my 'staff bio' component:

const StaffBio = (props) => {
return (
    <div className={`teamMemberOverlay ${props.active}`} onClick={props.onClick}>
        <div className="teamMemberExpanded">
            <h6>{props.name}</h6>
            <div className="seperator"></div>
            <p className="title">{props.title}</p>
        </div>
    </div>
);
}

Which is being used like this:

<StaffBio name="NAME HERE" title="TITLE HERE" active={this.state.active} onClick={this.showBio} />

So far I've got the images set up as follows:

<img src={PaulIllustration} className="staffPhoto" onClick={this.showBio} />

And lastly, my event handler:

showBio() {
    let toggle = this.state.active === 'is-active' ? '' : 'is-active';
    this.setState({active: toggle});
}

Upvotes: 0

Views: 622

Answers (1)

BravoZulu
BravoZulu

Reputation: 1140

class AboutUsSlider extends Component {
  constructor(props) {
    super(props);
    this.showBio = this.showBio.bind(this)
    this.next = this.next.bind(this)

    this.state = { active: null }
}

next() {
  this.refs.slider.slickNext()
}

showBio(id) {
  this.setState({active: id});
}
hideBio(){
  this.setState({active: null});
}

render() {
  var settings = {...}
  const people = [{name: 'Paul', title: 'some title'}, {name: 'Ben', title: 'other'}, ...];

return (
  <div>
  <Slider ref="slider" {...settings}>
    <div className="sliderPage">
      <h2>Meet our team</h2>
      <div className="seperator"></div>
      <div className="teamPhotos">
      { // When setting the index, you should use something unique, I'll use the name here.
       people.map((p, index) => 
           <img key={p.name} src={`${p.name} + 'Illustration'`} className="staffPhoto" onClick={() => this.showBio(index)}) />
      }
      </div>
      <Button BGColor="#009ECC" text="Our process" onClick={this.next} />
    </div>
  </Slider>
  { this.state.active && <StaffBio name={people[this.state.active]} title={people[this.state.active].title} onClick={this.hideBio}/>
  </div>
  )
}

EDITED

There are a couple of things you can do.

Each person probably has an id to identify it. So you could modify your showBio to look like this:

showBio(id) {
  this.setState({ active: id })
}

This way, you get which person is currently active in your state.

You also need to change your img

<img src={PaulIllustration} className="staffPhoto" onClick={() => this.showBio(PaulId)} />

Where PaulId would be different for each person.

And your StaffBio:

<StaffBio name="NAME HERE" title="TITLE HERE" active={this.state.active == personId} onClick={this.showBio} />


const StaffBio = (props) => {
  return (
  <div className={`teamMemberOverlay ${props.active ? 'is-active' : ''}`} onClick={props.onClick}>
    <div className="teamMemberExpanded">
        <h6>{props.name}</h6>
        <div className="seperator"></div>
        <p className="title">{props.title}</p>
    </div>
  </div>
  );
}

Upvotes: 1

Related Questions