React - 仅在单击项目时添加 class

React - Add a class only when an item is clicked

我有一个这样的无状态组件:

    import React from 'react';
    import PropTypes from 'prop-types';

    const Panel = (props) => {
      return(
        <div
          className={props.className}
          onClick={props.onClick}>
          <p>{props.firstChild}</p>
          <p>{props.secondChild}</p>
          <p>{props.thirdChild}</p>
        </div>
      )
    }

    Panel.propTypes = {
      onClick: PropTypes.func.isRequired,
      className:PropTypes.any.isRequired,
      firstChild: PropTypes.string.isRequired,
      secondChild: PropTypes.string.isRequired,
      thirdChild: PropTypes.string.isRequired,
    };

    export default Panel

我的 Class 组件是这样的:

    import React, { Component } from 'react';
    import Panel from './panel'

    class ImageGallery extends Component {
      constructor(props){
        super(props)
        this.state = {
          open: false,
        }
      }

      toggleOpen = () => {
        console.log('hi')
        this.setState({
          open: !this.state.open
        })
      }

      render() {
        return (
          <div className="panels">
            <Panel
              firstChild="Hey"
              secondChild="Let's"
              thirdChild="Talk"
              onClick={this.toggleOpen}
              className={this.state.open ? "panel panel1 open open-active " : "panel panel1"}
            />
            <Panel
              firstChild="Hey"
              secondChild="Give"
              thirdChild="Me"
              onClick={this.toggleOpen}
              className={this.state.open ? "panel panel2 open open-active " : "panel panel2"}
            />
          </div>
        )
      };
    }

    export default ImageGallery;

onClick 一个 Panel 组件希望这个组件将 openopen-active 类 添加到我的项目中。 目前一个项目上的 onClock 都打开了,但我希望两者分开处理。

我不确定如何以最干净的方式使用状态和 类。

感谢您的帮助

您需要单独的值来跟踪这些面板,如下所示。我没有测试代码,但应该是这样的。

 import React, { Component } from 'react';
    import Panel from './panel'

    class ImageGallery extends Component {
      constructor(props){
        super(props)
        this.state = {
          panel1: {
            open: false
          },
          panel2: {
            open: false
          }
        }
      }

      toggleOpen = (key) => {
        console.log('hi')
        this.setState({
          [key]: {
            open: !this.state[key].open
          }
        })
      }

      render() {
        return (
          <div className="panels">
            <Panel
              firstChild="Hey"
              secondChild="Let's"
              thirdChild="Talk"
              onClick={() => this.toggleOpen('panel1')}
              className={this.state.open ? "panel panel1 open open-active " : "panel panel1"}
            />
            <Panel
              firstChild="Hey"
              secondChild="Give"
              thirdChild="Me"
              onClick={() => this.toggleOpen('panel2')}
              className={this.state.open ? "panel panel2 open open-active " : "panel panel2"}
            />
          </div>
        )
      };
    }

    export default ImageGallery;

另外,为了便于管理类名,建议使用classnames包。

为每个 <Panel /> 组件添加一个名称:

<Panel
name="Foo"
isOpen={this.state.fooOpen}
...
/>
<Panel
name="Bar"
isOpen={this.state.barOpen}
...
/>

在您的处理程序中使用如下代码:

toggleOpen = event => {
    if(event.target.name === "Foo") {
        this.setState({fooOpen: true})
    } else {
        this.setState({barOpen: true})
    }
}

确保在您的 Panel 组件中将名称向下传递给您从中调用处理程序的元素。

有趣的是,我今天早上刚刚在我的应用程序中编写了与此非常相似的代码。

我是这样做的(如果您一次只想打开一个面板):您可以在此处的沙箱中看到它的工作原理。 https://codesandbox.io/s/mow9nyj958

import React, { Component } from 'react';
import Panel from './panel'

class ImageGallery extends Component {
  constructor(props){
    super(props)
    this.state = {
      openPanel: undefined,
    }
  }

  toggleOpen = (panelNumber) => {
    console.log('hi')
    this.setState(prevState => ({
      openPanel: (prevState.openPanel === panelNumber) ? undefined : panelNumber 
    }))
  }

  render() {
    return (
      <div className="panels">
        <Panel
          firstChild="Hey"
          secondChild="Let's"
          thirdChild="Talk"
          onClick={() => this.toggleOpen(1)}
          className={`panel panel1 ${(this.state.openPanel === 1) ? "open open-active" : ""}`}
        />
        <Panel
          firstChild="Hey"
          secondChild="Give"
          thirdChild="Me"
          onClick={() => this.toggleOpen(2)}
          className={`panel panel1 ${(this.state.openPanel === 2) ? "open open-active" : ""}`}
        />
      </div>
    )
  };
}

export default ImageGallery;  

但我假设您希望能够同时打开两个面板,因此您可以执行类似的操作。

class ImageGallery extends Component {
  constructor(props){
    super(props)
    this.state = {
      panel1Open: false,
      panel2Open: false
    }
  }

  toggleOpen = (panelNumber) => {
    console.log('hi')
    this.setState(prevState => {
      const key = `panel${panelNumber}Open`;
      return { [key]: !prevState[key] }
    })
  } 
  render() {
    return (
      <div className="panels">
        <Panel
          firstChild="Hey"
          secondChild="Let's"
          thirdChild="Talk"
          onClick={() => this.toggleOpen(1)}
          className={`panel panel1 ${this.state.panel1Open ? "open open-active" : ""}`}
        />
        <Panel
          firstChild="Hey"
          secondChild="Give"
          thirdChild="Me"
          onClick={() => this.toggleOpen(2)}
          className={`panel panel1 ${this.state.panel2Open ? "open open-active" : ""}`}
        />
      </div>
    )
  };
}