5

I have a .map() function where I'm iterating over an array and rendering elements, like so:

      {options.map((option, i) => (
        <TachyonsSimpleSelectOption
          options={options[i]}
          key={i}
          onClick={() => this.isSelected(i)}
          selected={this.toggleStyles("item")}
        />

I am toggling the state of a selected element like so:

isSelected (i) {
    this.setState({ selected: !this.state.selected }, () => { console.log(this.state.selected) })
}

Using a switch statement to change the styles:

  toggleStyles(el) {
    switch (el) {
      case "item":
        return this.state.selected ? "bg-light-gray" : "";
        break;
    }
  }

And then passing it in my toggleStyles method as props to the className of the TachyonsSimpleSelectOption Component.

Problem

The class is being toggled for all items in the array, but I only want to target the currently clicked item.

Link to Sandbox.

What am I doing wrong here?

3 Answers 3

5

You're using the selected state incorrectly.

In your code, to determine whether it is selected or not, you depends on that state, but you didn't specify which items that is currently selected.

Instead saving a boolean state, you can store which index is currently selected so that only specified item is affected.

This may be a rough answer, but I hope I can give you some ideas.

on your render:

{options.map((option, i) => (
  <TachyonsSimpleSelectOption
    options={options[i]}
    key={i}
    onClick={() => this.setState({ selectedItem: i })}
    selected={this.determineItemStyle(i)}
   />
))}

on the function that will determine the selected props value:

determineItemStyle(i) {
  const isItemSelected = this.state.selectedItem === i;
  return isItemSelected ? "bg-light-gray" : "";
}

Hope this answer will give you some eureka moment

Sign up to request clarification or add additional context in comments.

1 Comment

makes total sense. Thanks!
0

You are not telling react which element is toggled. Since the state has just a boolean value selected, it doesn't know which element is selected.

In order to do that, change your isSelected function to :

isSelected (i) {
  this.setState({ selected: i }, () => { 
    console.log(this.state.selected) })
}

Now, the React state knows that the item on index i is selected. Use that to toggle your class now.

In case you want to store multiple selected items, you need to store an array of indices instead of just one index

Comments

0

TachyonsSimpleSelectOption.js:

import React from 'react';

class Option extends React.Component {
  render() {
    const { selected, name } = this.props;
    return(
       <h1 
        onClick={() => this.props.onClick()}
        style={{backgroundColor: selected ? 'grey' : 'white'}}
       >Hello {name}!</h1>
    )
  }
}
export default Option;

index.js:

import React from "react";
import { render } from "react-dom";
import TachyonsSimpleSelectOption from "./TachyonsSimpleSelectOption";

const options = ["apple", "pear", "orange"];

const styles = {
  selected: "bg-light-gray"
};

class Select extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
      selected: []
    };

    this.handleClick = this.handleClick.bind(this);
    this.handleBlur = this.handleBlur.bind(this);
    this.isSelected = this.isSelected.bind(this);
  }

  handleBlur() {
    this.toggleMenu(close);
  }

  handleClick(e) {
    this.toggleMenu();
  }

  toggleMenu(close) {
    this.setState(
      {
        open: !this.state.open
      },
      () => {
        this.toggleStyles("menu");
      }
    );
  }

  toggleStyles(el, index) {
    switch (el) {
      case "menu":
        return this.state.open ? "db" : "dn";
        break;
      case "item":
        const { selected } = this.state;
        return selected.indexOf(index) !== -1;
        break;
    }
  }

  isSelected(i) {
    let { selected } = this.state;
    if (selected.indexOf(i) === -1) {
      selected.push(i);
    } else {
      selected = selected.filter(index => index !== i);
    }
    this.setState({ selected});
  }

  render() {
    const { options } = this.props;
    return (
      <div
        className="flex flex-column ba"
        onBlur={this.handleBlur}
        tabIndex={0}
      >
        <div className="flex-row pa3" onClick={this.handleClick}>
          <span className="flex-grow-1 w-50 dib">Title</span>
          <span className="flex-grow-1 w-50 dib tr">^</span>
        </div>
        <div className={this.toggleStyles("menu")}>
          {options.map((option, i) => (
            <TachyonsSimpleSelectOption
              name={options[i]}
              key={i}
              onClick={() => this.isSelected(i)}
              selected={this.toggleStyles("item", i)}
            />
          ))}
        </div>
      </div>
    );
  }
}

render(<Select options={options} />, document.getElementById("root"));

And Link to Sandbox.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.