【问题标题】:Toggle Class in React在 React 中切换类
【发布时间】:2016-07-24 00:30:23
【问题描述】:

我在一个有菜单按钮的项目中使用 react。

<a ref="btn" href="#" className="btn-menu show-on-small"><i></i></a>

还有一个 Sidenav 组件,例如:

<Sidenav ref="menu" />

我编写了以下代码来切换菜单:

class Header extends React.Component {

    constructor(props){
        super(props);
        this.toggleSidenav = this.toggleSidenav.bind(this);
    }

    render() {
        return (
          <div className="header">
            <i className="border hide-on-small-and-down"></i>
            <div className="container">
          <a ref="btn" href="#" className="btn-menu show-on-small"><i></i></a>
          <Menu className="menu hide-on-small-and-down"/>
          <Sidenav />
        </div>
          </div>
        )
    }

    toggleSidenav() {
        this.refs.btn.classList.toggle('btn-menu-open');
    }

    componentDidMount() {
        this.refs.btn.addEventListener('click', this.toggleSidenav);
    }

    componentWillUnmount() {
        this.refs.btn.removeEventListener('click', this.toggleSidenav);
    }
}

问题是this.refs.sidenav 不是 DOM 元素,我无法在他身上添加类。

谁能解释我如何在Sidenav 组件上切换类,就像我在按钮上做的那样?

【问题讨论】:

  • 您做错了,因为您使用 DOM 而不是 React 组件渲染方法更改类和事件处理程序。你能添加你的组件的代码吗?
  • 已更新,请告诉我如何做得更好
  • @Hiero 这是对 React 的根本误解。您实际上是在 DOM 中存储状态,您应该不惜一切代价避免这种情况。相反,您应该跟踪state 中按钮的可见性,并根据该状态在render() 中动态声明className - 请参阅facebook.github.io/react/docs/…

标签: javascript reactjs


【解决方案1】:

react 中的切换功能

首先你应该创建构造函数 像这样

constructor(props) {
        super(props);
        this.state = {
            close: true,
        };
    }

然后创建一个这样的函数

yourFunction = () => {
        this.setState({
            close: !this.state.close,
        });
    };

然后像这样使用

render() {
        const {close} = this.state;
        return (

            <Fragment>

                 <div onClick={() => this.yourFunction()}></div>

                 <div className={close ? "isYourDefaultClass" : "isYourOnChangeClass"}></div>

            </Fragment>
        )
    }
}

请给出更好的解决方案

【讨论】:

    【解决方案2】:

    对于任何在 2019 年阅读本文的人,在 React 16.8 发布后,请查看React Hooks。它确实简化了组件中的状态处理。文档写得非常好,并附有您所需要的示例。

    【讨论】:

      【解决方案3】:

      如果您希望 React 正确有效地渲染您的 DOM,您必须使用组件的 State 来更新组件参数,例如 Class Name。

      更新:我更新了示例以在单击按钮时切换侧边菜单。这不是必需的,但您可以看到它是如何工作的。正如我所展示的,您可能需要使用“this.state”与“this.props”。我习惯使用 Redux 组件。

      constructor(props){
          super(props);
      }
      
      getInitialState(){
        return {"showHideSidenav":"hidden"};
      }
      
      render() {
          return (
              <div className="header">
                  <i className="border hide-on-small-and-down"></i>
                  <div className="container">
                      <a ref="btn" onClick={this.toggleSidenav.bind(this)} href="#" className="btn-menu show-on-small"><i></i></a>
                      <Menu className="menu hide-on-small-and-down"/>
                      <Sidenav className={this.props.showHideSidenav}/>
                  </div>
              </div>
          )
      }
      
      toggleSidenav() {
          var css = (this.props.showHideSidenav === "hidden") ? "show" : "hidden";
          this.setState({"showHideSidenav":css});
      }
      

      现在,当您切换状态时,组件将更新并更改 sidenav 组件的类名。您可以使用 CSS 使用类名显示/隐藏 sidenav。

      .hidden {
         display:none;
      }
      .show{
         display:block;
      }
      

      【讨论】:

      • 为什么不是 this.state.showHideSidenav?
      • 在那里使用 State 可能是对的。我不记得了。我习惯于将 Redux 与 React 一起使用,这会强制所有 UI 更新进入组件 Props 而不是状态。两者都试一下,然后用哪个都行:)
      • 如果使用 ES6 类在构造函数中设置初始状态。参考:stackoverflow.com/questions/30668326/…
      【解决方案4】:

      Ori Drori 的评论是正确的,你没有这样做“反应方式”。在 React 中,最好不要使用 DOM 更改类和事件处理程序。在 React 组件的 render() 方法中执行此操作;在这种情况下,这将是 sideNav 和您的 Header。如何在您的代码中完成此操作的粗略示例如下。

      标题

      class Header extends React.Component {
      constructor(props){
          super(props);
      }
      
      render() {
          return (
              <div className="header">
                  <i className="border hide-on-small-and-down"></i>
                  <div className="container">
                      <a ref="btn" href="#" className="btn-menu show-on-small"
                      onClick=this.showNav><i></i></a>
                      <Menu className="menu hide-on-small-and-down"/>
                      <Sidenav ref="sideNav"/>
                  </div>
              </div>
          )
      }
      
      showNav() {
        this.refs.sideNav.show();
      }
      }
      

      侧向导航

       class SideNav extends React.Component {
         constructor(props) {
           super(props);
           this.state = {
             open: false
           }
         }
      
         render() {
           if (this.state.open) {
             return ( 
               <div className = "sideNav">
                  This is a sidenav 
               </div>
             )
           } else {
             return null;
           }
      
         }
      
         show() {
           this.setState({
             open: true
           })
         }
       }
      

      您可以在此处看到,我们不是切换类,而是使用组件的状态来呈现 SideNav。这种方式或类似方式是使用 react 的整个前提。如果您使用的是引导程序,那么有一个库将引导程序元素与反应的处理方式集成在一起,允许您使用相同的元素但在它们上设置状态,而不是直接操作 DOM。可以在这里找到 - https://react-bootstrap.github.io/

      希望这会有所帮助,并享受使用 React 的乐趣!

      【讨论】:

      • 谢谢马丁,现在我明白了,但是通过推送到 this.refs.btn 的 classList 就可以了,还是我也应该制作那个组件?
      • Aaron Francos 方式是一个很好的干净实现,可以解决您的问题。不过,就我个人而言,我认为让 React 组件来代表 UI 的每个组件是件好事。它使代码保持模块化、简洁,并使您可以非常轻松地构建应用程序并减少耦合。这真的取决于个人喜好,只要你设置组件的状态而不是直接操作 DOM,你就走在了正确的轨道上。 :)
      • 这是处理这个问题的更“反应”的方式。这对 DOM 的影响应该很小。我的方法是一种很酷的简单方法,但不可否认,我的反应不如现在先进。现在,我将创建一个带有条件渲染的组件。不错的回复! reactjs.org/docs/conditional-rendering.html
      【解决方案5】:

      refs 不是 DOM 元素。为了找到一个DOM元素,你需要先使用findDOMNode menthod。

      做这个

      var node = ReactDOM.findDOMNode(this.refs.btn);
      node.classList.toggle('btn-menu-open');
      

      或者,您可以像这样使用(几乎是实际代码)

      this.state.styleCondition = false;
      
      
      <a ref="btn" href="#" className={styleCondition ? "btn-menu show-on-small" : ""}><i></i></a>
      

      然后您可以根据您的状态更改条件更改styleCondition

      【讨论】:

      • 但是为什么你给我看一个向我的按钮添加类的例子,因为我的问题是如何在 Sidenav 组件上添加类?
      • 只需将btn 更改为menu。这没什么大不了的。我只举了一个例子,两种情况的基本编码都是一样的
      • 我建议选项 2,因为它面临 React 标准。是的,这是最佳做法
      • 你确定它不是 DOM 节点吗? (或者也许事情发生了变化......?)因为我可以很高兴地做像this.refs.nav.getElementsByTagName('ul')[0].offsetHeight这样的事情......
      • @Bikas 谢谢我喜欢的第二个选项
      猜你喜欢
      • 2016-10-28
      • 2017-07-26
      • 1970-01-01
      • 1970-01-01
      • 2021-06-17
      • 2021-09-10
      • 2019-06-07
      • 2018-02-21
      相关资源
      最近更新 更多