最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to toggle css class of a single element in a .map() function in React - Stack Overflow

programmeradmin1浏览0评论

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?

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?

Share Improve this question asked Mar 14, 2018 at 3:56 a7dca7dc 3,4268 gold badges37 silver badges57 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 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

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

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.

发布评论

评论列表(0)

  1. 暂无评论