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

javascript - React - click event triggers all siblings at once - Stack Overflow

programmeradmin3浏览0评论

How could I have each <li /> that receives an onClick event to only fire individually one at a time?

My intent is to change colors and show/hide content based on a click event. It works, However upon clicking on a given <li/> all of its siblings get fired at the same time as well.

How could I prevent that?

here's sandbox code

function App() {
  return (
    <div className="App">
      <Market />
    </div>
  );
}

class Market extends Component {
  constructor() {
    super();
    this.state = {
      isColor: false,
      isShow: false,
      fruits: ["Apple", "Banana", "Peach"]
    };
  }

  handleToggle = () => {
    this.setState(currentState => ({
      isColor: !currentState.isColor,
      isShow: !currentState.isShow
    }));
  };

  render() {
    const fruits = this.state.fruits.map((item, i) => (
      <li
        key={i}
        className={this.state.isColor ? "blue" : "red"}
        onClick={this.handleToggle}
      >
        {item}
        <span className={this.state.isShow ? "show" : "hide"}>Show Text</span>
      </li>
    ));
    return <ul>{fruits}</ul>;
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

How could I have each <li /> that receives an onClick event to only fire individually one at a time?

My intent is to change colors and show/hide content based on a click event. It works, However upon clicking on a given <li/> all of its siblings get fired at the same time as well.

How could I prevent that?

here's sandbox code

function App() {
  return (
    <div className="App">
      <Market />
    </div>
  );
}

class Market extends Component {
  constructor() {
    super();
    this.state = {
      isColor: false,
      isShow: false,
      fruits: ["Apple", "Banana", "Peach"]
    };
  }

  handleToggle = () => {
    this.setState(currentState => ({
      isColor: !currentState.isColor,
      isShow: !currentState.isShow
    }));
  };

  render() {
    const fruits = this.state.fruits.map((item, i) => (
      <li
        key={i}
        className={this.state.isColor ? "blue" : "red"}
        onClick={this.handleToggle}
      >
        {item}
        <span className={this.state.isShow ? "show" : "hide"}>Show Text</span>
      </li>
    ));
    return <ul>{fruits}</ul>;
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Share Improve this question asked Nov 16, 2018 at 19:10 Null isTrueNull isTrue 1,9368 gold badges31 silver badges50 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 5

Your <li>s are not all firing. All of your elements are checking state to see if color and visible is true. So you have one state, for three elements, when one is true, they all are true.

You either want to make an object in the state for each fruit, or better yet, create a new ponent for the list items that each have their own state, and pass the fruit name through a prop.

I've forked your sandbox and created a quick example of what this looks like. This is a core react concept of breaking things out into reusable modules, and having ponents manage their own state when possible. It will really benefit you in the long run to really get this idea down now, so I hope this helps.

All the click handlers are not fired simultaneously, but you keep one variable to indicate if all of them are shown or not.

You could instead keep an object in your state in which you keep key-value pairs indicating if an item is shown or not.

Example

class Market extends React.Component {
  state = {
    fruits: ["Apple", "Banana", "Peach"],
    isShown: {}
  };

  handleToggle = item => {
    this.setState(currentState => ({
      isShown: { ...currentState.isShown, [item]: !currentState.isShown[item] }
    }));
  };

  render() {
    return (
      <ul>
        {this.state.fruits.map((item, i) => (
          <li
            key={i}
            style={{
              backgroundColor: this.state.isShown[item] ? "blue" : "red"
            }}
            onClick={() => this.handleToggle(item)}
          >
            {item}
            <span
              style={{
                display: this.state.isShown[item] ? "inline-block" : "none"
              }}
            >
              Show Text
            </span>
          </li>
        ))}
      </ul>
    );
  }
}

ReactDOM.render(<Market />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

Here's a working sandbox for the approach suggested by @SpeedOfRound. Creating an independent ponent for every li so that that elements has its own state. I don't know this approach is efficient pared to the answer by @Tholle.

SandBox [ https://codesandbox.io/s/1vyonx0zrl ]

发布评论

评论列表(0)

  1. 暂无评论