反应-更新状态以从选项卡导航添加/删除活动类

时间:2019-07-17 13:36:12

标签: javascript reactjs

我在页面顶部有一个标签导航,我想在单击该标签时向其添加“活动”类,并确保该标签不在其他任何标签上。

到目前为止,我已经将'active'类添加到第一个选项卡,但是如果您单击任何其他选项卡,则不会更新。因此,无论您单击什么,第一个选项卡始终是活动选项卡。

import React from 'react'
import { string } from 'prop-types'

class TabNav extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      currentTab: ''
    }

    this.handleClick = this.handleClick.bind(this)
    this.createTabItems = this.createTabItems.bind(this)
  }

  shouldComponentUpdate (nextProps, nextState) {
    return nextProps.navItems !== this.props.navItems
  }

  handleClick (currentTab) {
    this.setState({
      currentTab: currentTab
    })
    this.createTabItems()
  }

  createTabItems () {
    const { navItems = false } = this.props
    if (!navItems) return false
    const splitItems = navItems.split(',')
    if (!splitItems.length) return false
    return splitItems.map((item, currentTab) => {
      const items = item.split('_')
      if (items.length !== 3) return null
      const itemLink = items[1]
      return (
        <li key={currentTab} className={this.state.currentTab == currentTab ? 'side-nav-tab active' : 'side-nav-tab'} onClick={this.handleClick.bind(this, currentTab)}>
            <a href={itemLink}>
              <p>{ items[0] }</p>
            </a>
        </li>
      )
    })
  }

  render () {
    const tabItems = this.createTabItems()
    if (!tabItems) return null
    return (
      <div>
        <ul id='tabNavigation'>
          {tabItems}
        </ul>
      </div>
    )
  }
}

TabNav.propTypes = {
  navItems: string.isRequired
}

export default TabNav

我也尝试过在setState中异步调用this.createTabItems来尝试强制进行更新,但这没有用:

 handleClick (currentTab) {
    this.setState({
      currentTab: currentTab
    }, () => this.createTabItems)
  }

3 个答案:

答案 0 :(得分:0)

我认为您的shouldComponentUpdate引起了问题。您可以尝试删除它吗?另外,您不需要在this.createTabItems

中呼叫handleClick()

答案 1 :(得分:0)

我觉得这里需要进行思维转变,以便更加声明性地思考,您无需在要创建选项卡时告诉React,它会根据render方法和传递给它的数据来确定这一点。

我已经删除了您的componentShouldUpdate函数,因为React已经为您完成了这些道具的比较。我还按索引跟踪了所选项目,因为它简化了我的思维。

尝试这样的事情:

import React from 'react';
import { string } from 'prop-types';

class TabNav extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      selectedIndex: 0
    };
  }

  handleClick = index => {
    this.setState({
      selectedIndex: index
    });
  };

  render() {
    const { navItems = [] } = this.props;

    return (
      <div>
        <ul id="tabNavigation">
          {navItems.map((navItem, index) => {
            if (navItem.length !== 3) return;

            const [text, link] = navItem;

            return (
              <li
                className={
                  this.state.selectedIndex === index
                    ? 'side-nav-tab active'
                    : 'side-nav-tab'
                }
                onClick={this.handleClick.bind(null, index)}
              >
                <a href={link}>
                  <p>{text}</p>
                </a>
              </li>
            );
          })}
          }
        </ul>
      </div>
    );
  }
}

TabNav.propTypes = {
  navItems: string.isRequired
};

export default TabNav;

那里还有其他一些变化,例如从数组中解构而不是使用索引,这样可以更清楚地从navItem数组中提取出什么属性。

我还对handleClick函数使用了粗箭头功能,因为这意味着您不必绑定到构造函数中的this

答案 2 :(得分:0)

您遇到两个问题,首先是您在函数中使用this的方式,其次是您的shouldUpdateComponent,就像在我前面提到的另一个一样。如果要使用this引用类,则需要使用箭头函数。请记住,ES6箭头函数使用词法作用域,这意味着this引用了包含该函数的代码。我通过一个有效的示例在下面的代码中进行了更改。

class TabNav extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      currentTab: ''
    }

    this.handleClick = this.handleClick.bind(this)
    this.createTabItems = this.createTabItems.bind(this)
  }

  handleClick (currentTab) {
    this.setState({
      currentTab: currentTab
    })
  }

  createTabItems = () => {
    const { navItems = false } = this.props
    if (!navItems) return false
   
    const splitItems = navItems.split(',')
    if (!splitItems.length) return false
    return splitItems.map((item, currentTab) => {
      const items = item.split('_')
      if (items.length !== 3) return null
      const itemLink = items[1]
      return (
        <li key={currentTab} className={this.state.currentTab == currentTab ? 'side-nav-tab active' : 'side-nav-tab'} onClick={this.handleClick.bind(null, currentTab)}>
            <a href={itemLink}>
              <p>{ items[0] }</p>
            </a>
        </li>
      )
    })
  }

  render () {
    const tabItems = this.createTabItems()
    if (!tabItems) return null
    return (
      <div>
        <ul id='tabNavigation'>
          {tabItems}
        </ul>
      </div>
    )
  }
}

class Nav extends React.Component {
  render() {
    return(
     <TabNav navItems={'Test1_#_Test1,Test2_#_Test2'} />)
  }
}


ReactDOM.render(<Nav />, document.getElementById('root'))
.active {
  font-size: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

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