REACT - toggle class onclick

后端 未结 14 1721
长情又很酷
长情又很酷 2020-11-27 11:40

I am trying to figure out how to toggle an active class onClick to change CSS properties.

I have taken many approaches, and read many SO answers. Using

相关标签:
14条回答
  • 2020-11-27 12:07

    React has a concept of components state, so if you want to Toggle, use setState:

    1. App.js
    import React from 'react';
    
    import TestState from './components/TestState';
    
    class App extends React.Component {
      render() {
        return (
          <div className="App">
            <h1>React State Example</h1>
            <TestState/>
          </div>
        );
      }
    }
    
    export default App;
    
    1. components/TestState.js
    import React from 'react';
    
    class TestState extends React.Component
    {
    
        constructor()
        {
            super();
            this.state = {
                message: 'Please subscribe',
                status: "Subscribe"
            }
        }
    
        changeMessage()
        {
            if (this.state.status === 'Subscribe')
            {
                this.setState({message : 'Thank You For Scubscribing.', status: 'Unsubscribe'})
            }
            else
            {
                this.setState({ message: 'Please subscribe', status: 'Subscribe' })
            }
        }
        
        render()
        {
            return (
                <div>
                    <h1>{this.state.message}</h1>
            <button onClick={()=> this.changeMessage() } >{this.state.status}</button>
                </div>
            )
        }
    }
    
    export default TestState;
    
    1. Output

    0 讨论(0)
  • 2020-11-27 12:08

    Just wanted to add my approach. Using hooks and context provider.

    Nav.js

    function NavBar() {
      const filterDispatch = useDispatchFilter()
      const {filter} = useStateFilter()
      const activeRef = useRef(null)
      const completeRef = useRef(null)
      const cancelRef = useRef(null)
    
      useEffect(() => {
        let activeClass = '';
        let completeClass = '';
        let cancelClass = '';
        if(filter === ACTIVE_ORDERS){
          activeClass='is-active'
        }else if ( filter === COMPLETE_ORDERS ){
          completeClass='is-active'
        }else if(filter === CANCEL_ORDERS ) {
          cancelClass='is-active'
        }
        activeRef.current.className = activeClass
        completeRef.current.className = completeClass
        cancelRef.current.className = cancelClass
      }, [filter])
    
      return (
        <div className="tabs is-centered">
          <ul>
            <li ref={activeRef}>
              <button
                className="button-base"
                onClick={() => filterDispatch({type: 'FILTER_ACTIVE'})}
              >
                Active
              </button>
            </li>
    
            <li ref={completeRef}>
              <button
                className="button-base"
                onClick={() => filterDispatch({type: 'FILTER_COMPLETE'})}
              >
                Complete
              </button>
            </li>
            <li ref={cancelRef}>
              <button
                className={'button-base'}
                onClick={() => filterDispatch({type: 'FILTER_CANCEL'})}
              >
                Cancel
              </button>
            </li>
          </ul>
        </div>
      )
    }
    
    export default NavBar
    

    filterContext.js

    export const ACTIVE_ORDERS = [
      "pending",
      "assigned",
      "pickup",
      "warning",
      "arrived",
    ]
    export const COMPLETE_ORDERS = ["complete"]
    export const CANCEL_ORDERS = ["cancel"]
    
    const FilterStateContext = createContext()
    const FilterDispatchContext = createContext()
    
    export const FilterProvider = ({ children }) => {
      const [state, dispatch] = useReducer(FilterReducer, { filter: ACTIVE_ORDERS })
      return (
        <FilterStateContext.Provider value={state}>
          <FilterDispatchContext.Provider value={dispatch}>
            {children}
          </FilterDispatchContext.Provider>
        </FilterStateContext.Provider>
      )
    }
    export const useStateFilter = () => {
      const context = useContext(FilterStateContext)
      if (context === undefined) {
        throw new Error("place useStateMap within FilterProvider")
      }
      return context
    }
    export const useDispatchFilter = () => {
      const context = useContext(FilterDispatchContext)
      if (context === undefined) {
        throw new Error("place useDispatchMap within FilterProvider")
      }
      return context
    }
    
    
    export const FilterReducer = (state, action) => {
      switch (action.type) {
        case "FILTER_ACTIVE":
          return {
            ...state,
            filter: ACTIVE_ORDERS,
          }
        case "FILTER_COMPLETE":
          return {
            ...state,
            filter: COMPLETE_ORDERS,
          }
        case "FILTER_CANCEL":
          return {
            ...state,
            filter: CANCEL_ORDERS,
          }
      }
      return state
    }
    

    Works fast, and replaces redux.

    0 讨论(0)
  • 2020-11-27 12:12

    A good sample would help to understand things better:

    HTML

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

    CSS

    .box {
      display: block;
      width: 200px;
      height: 200px;
      background-color: gray;
      color: white;
      text-align: center;
      vertical-align: middle;
      cursor: pointer;
    }
    .box.green {
      background-color: green; 
    }
    

    React code

    class App extends React.Component {
      constructor(props) {
        super(props);
        this.state = {addClass: false}
      }
      toggle() {
        this.setState({addClass: !this.state.addClass});
      }
      render() {
        let boxClass = ["box"];
        if(this.state.addClass) {
          boxClass.push('green');
        }
        return(
            <div className={boxClass.join(' ')} onClick={this.toggle.bind(this)}>{this.state.addClass ? "Remove a class" : "Add a class (click the box)"}<br />Read the tutorial <a href="http://www.automationfuel.com" target="_blank">here</a>.</div>       
        );
      }
    }
    ReactDOM.render(<App />, document.getElementById("root"));
    
    0 讨论(0)
  • 2020-11-27 12:12

    I started learning React recently and wanted to build a tab just to see how far my knowledge has gone. I came across this and decided to implement something without redux. I kind of feel the answers don't reflect what op wants to achieve. He wants only one active component but the answers here will set all components active. I have given it a shot.

    Below is a tab file

    import React, { Component } from 'react';
    
    
    class Tab extends Component {
    
        render(){
            const tabClassName = "col-xs-3 tab-bar";
            const activeTab = this.props.activeKey === this.props.keyNumber ? "active-tab" : null;
            return (
                    <div 
                        className = {`${tabClassName} ${activeTab}`}
                        onClick={()=>this.props.onClick(this.props.keyNumber)}
                    >
                        I am here
                    </div>
            );
        }
    }
    
    
    export default Tab;
    

    The tabs file...

    import React, { Component } from 'react';
    import Tab from './tab';
    
    class Tabs extends Component {
    
        constructor(props){
            super(props);
    
            this.state = {
                currentActiveKey: 0,
                tabNumber: 2
            };
    
            this.setActive = this.setActive.bind(this);
            this.setTabNumber = this.setTabNumber.bind(this);
        }
    
        setTabNumber(number){
            this.setState({
                tabNumber: number
            });
        }
    
        setActive (key){
            this.setState({
                currentActiveKey: key 
            });
        }
    
        render(){
            let tabs = [];
            for(let i = 0; i <= this.state.tabNumber; i++){
                let tab = <Tab key={i} keyNumber={i} onClick={this.setActive} activeKey={this.state.currentActiveKey}/>;
                tabs.push(tab);
            }
            return (
                <div className="row">
                    {tabs}
                </div>
            );
        }
    }
    
    
    export default Tabs;
    

    your index file...

    import React from 'react';
    import ReactDOM from 'react-dom';
    import Tabs from './components/tabs';
    
    
    ReactDOM.render(
        <Tabs />
      , document.querySelector('.container'));
    

    and the css

    .tab-bar {
        margin: 10px 10px;
        border: 1px solid grey;
    }
    
    .active-tab {
        border-top: 1px solid red;
    }
    

    This is a skeleton of something I want to improve on so increasing the tabNumber beyond 4 will break the css.

    0 讨论(0)
  • 2020-11-27 12:14

    Here is a code I came Up with:

    import React, {Component} from "react";
    import './header.css'
    
    export default class Header extends Component{
        state = {
            active : false
        };
    
    
        toggleMenuSwitch = () => {
            this.setState((state)=>{
                return{
                    active: !state.active
                }
            })
        };
        render() {
            //destructuring
            const {active} = this.state;
    
            let className = 'toggle__sidebar';
    
            if(active){
                className += ' active';
            }
    
            return(
                <header className="header">
                    <div className="header__wrapper">
                        <div className="header__cell header__cell--logo opened">
                            <a href="#" className="logo">
                                <img src="https://www.nrgcrm.olezzek.id.lv/images/logo.svg" alt=""/>
                            </a>
                            <a href="#" className={className}
                               onClick={ this.toggleMenuSwitch }
                               data-toggle="sidebar">
                                <i></i>
                            </a>
                        </div>
                        <div className="header__cell">
    
                        </div>
                    </div>
                </header>
            );
        };
    };
    
    0 讨论(0)
  • 2020-11-27 12:15

    React has a concept of components state, so if you want to switch it, do a setState:

    constructor(props) {
      super(props);
    
      this.addActiveClass= this.addActiveClass.bind(this);
      this.state = {
        isActive: false
      }
    }
    
    addActiveClass() {
      this.setState({
        isActive: true
      })
    }
    

    In your component use this.state.isActive to render what you need.

    This gets more complicated when you want to set state in component#1 and use it in component#2. Just dig more into react unidirectional data flow and possibly redux that will help you handle it.

    0 讨论(0)
提交回复
热议问题