REACT - Klasse per Mausklick umschalten

95

Ich versuche herauszufinden, wie eine aktive Klasse umgeschaltet werden kann onClick, um die CSS-Eigenschaften zu ändern.

Ich habe viele Ansätze gewählt und viele SO-Antworten gelesen. Mit jquery wäre es relativ einfach, aber ich kann nicht herausfinden, wie man das mit reagieren macht. Mein Code ist unten. Kann mir jemand raten, wie ich das machen soll?

Ist dies möglich, ohne für jedes Element eine neue Komponente zu erstellen?

class Test extends Component(){

    constructor(props) {

    super(props);
    this.addActiveClass= this.addActiveClass.bind(this);

  }

  addActiveClass() {

    //not sure what to do here

  }

    render() {
    <div>
      <div onClick={this.addActiveClass}>
        <p>1</p>
      </div>
      <div onClick={this.addActiveClass}>
        <p>2</p>
      </div>
        <div onClick={this.addActiveClass}>
        <p>3</p>
      </div>
    </div>
  }

}
Peter Flanagan
quelle

Antworten:

86

Verwenden Sie state. Reacts docs sind hier .

class MyComponent extends Component {
    constructor(props) {
        super(props);
        this.addActiveClass= this.addActiveClass.bind(this);
        this.state = {
            active: false,
        };
    }
    toggleClass() {
        const currentState = this.state.active;
        this.setState({ active: !currentState });
    };

    render() {
        return (
            <div 
                className={this.state.active ? 'your_className': null} 
                onClick={this.toggleClass} 
            >
                <p>{this.props.text}</p>
            </div>
        )
  }
}

class Test extends Component {
    render() {
        return (
            <div>
                <MyComponent text={'1'} />
                <MyComponent text={'2'} />
            </div>
        );
    }
}
cssko
quelle
3
Gibt es eine Möglichkeit, dies zu tun, ohne eine zusätzliche Komponente zu erstellen?
Peter Flanagan
2
Sie möchten komplexe Komponenten in kleinere Komponenten
aufteilen,
1
Ich habe die Komponente aufgelöst, aber dies fügt activejedem Element beim Klicken immer noch hinzu . Ich möchte nur, dass ein Element eine aktive Klasse hat
Peter Flanagan
1
Dies kann nicht als umgeschaltete "aktive" Klasse bezeichnet werden, da die aktiven Klassen anderer Elemente noch vorhanden sind.
Dat TT
6
können Sie bitte die Antwort aktualisieren, um onClickim Gegensatz zu allen Kleinbuchstaben zu verwenden, wie Sie falsch haben
Peter Flanagan
24

Ich würde es vorziehen, den "&&" -Operator für die Inline-if-Anweisung zu verwenden. Meiner Meinung nach gibt es auf diese Weise eine sauberere Codebasis.

Im Allgemeinen könnten Sie so etwas tun

render(){
return(
  <div>
    <button className={this.state.active && 'active'}
      onClick={ () => this.setState({active: !this.state.active}) }>Click me</button>
  </div>
)
}

Denken Sie daran, dass die Pfeilfunktion die ES6-Funktion ist, und denken Sie daran, den Wert 'this.state.active' in class constructor () {} festzulegen

this.state = { active: false }

oder wenn Sie CSS in JSX einfügen möchten, können Sie dies auf diese Weise tun

<button style={this.state.active && style.button} >button</button>

und Sie können style json variable deklarieren

const style = { button: { background:'red' } }

Denken Sie daran, camelCase in JSX-Stylesheets zu verwenden.

Jimi Pajala
quelle
2
Dies ist die einfachste Methode, um einfache Klassennamen für Komponenten umzuschalten.
SeaWarrior404
12

Nun, Ihre addActiveClass muss wissen, was angeklickt wurde. So etwas könnte funktionieren (beachten Sie, dass ich die Informationen hinzugefügt habe, welche Divs als Statusarray aktiv sind, und dass onClick jetzt die Informationen übergibt, auf die als Parameter geklickt wurde, wonach der Status entsprechend aktualisiert wird - es gibt sicherlich intelligentere Möglichkeiten dazu mach es, aber du kommst auf die Idee).

class Test extends Component(){

  constructor(props) {
    super(props);
    this.state = {activeClasses: [false, false, false]};
    this.addActiveClass= this.addActiveClass.bind(this);
  }

  addActiveClass(index) {
    const activeClasses = [...this.state.activeClasses.slice(0, index), !this.state.activeClasses[index], this.state.activeClasses.slice(index + 1)].flat();
    this.setState({activeClasses});
  }

  render() {
    const activeClasses = this.state.activeClasses.slice();
    return (
      <div>
        <div className={activeClasses[0]? "active" : "inactive"} onClick={() => this.addActiveClass(0)}>
          <p>0</p>
        </div>
        <div className={activeClasses[1]? "active" : "inactive"} onClick={() => this.addActiveClass(1)}>
          <p>1</p>
        </div>
          <div  onClick={() => this.addActiveClass(2)}>
          <p>2</p>
        </div>
      </div>
    );
  }
}
Bane Bojanić
quelle
9

Sie können dies auch mit Haken tun .

function MyComponent (props) {
  const [isActive, setActive] = useState(false);

  const toggleClass = () => {
    setActive(!isActive);
  };

  return (
    <div 
      className={isActive ? 'your_className': null} 
      onClick={toggleClass} 
    >
      <p>{props.text}</p>
    </div>
   );
}  

quelle
4

Mit React können Sie jeder ID / jedem Element eine Umschaltklasse hinzufügen. Versuchen Sie es

style.css

.hide-text{
    display: none !important;
    /* transition: 2s all ease-in 0.9s; */
  }
.left-menu-main-link{
    transition: all ease-in 0.4s;
}
.leftbar-open{
    width: 240px;
    min-width: 240px;
    /* transition: all ease-in 0.4s; */
}
.leftbar-close{
    width: 88px;
    min-width:88px;
    transition: all ease-in 0.4s;
}

fileName.js

......
    ToggleMenu=()=>{
             this.setState({
                isActive: !this.state.isActive
              })
              console.log(this.state.isActive)
        }
        render() {
            return (
                <div className={this.state.isActive===true ? "left-panel leftbar-open" : "left-panel leftbar-close"} id="leftPanel">
                    <div className="top-logo-container"  onClick={this.ToggleMenu}>
                            <span className={this.state.isActive===true ? "left-menu-main-link hide-from-menu" : "hide-text"}>Welcome!</span>
                    </div>

                    <div className="welcome-member">
                        <span className={this.state.isActive===true ? "left-menu-main-link hide-from-menu" : "hide-text"}>Welcome<br/>SDO Rizwan</span>
                    </div>
    )
    }
......
Rizo
quelle
Ich möchte hinzufügen, dass Sie den folgenden Codestil verwenden können, wenn Sie eine statische Klasse haben, die Sie nicht für jede der "isActive" -Anweisungen definieren möchten:className={`left-panel ${this.state.isActive===true ? 'leftbar-open' : 'leftbar-close'}`}
Zeliax
4

React hat ein Konzept für den Komponentenstatus. Wenn Sie ihn also wechseln möchten, führen Sie Folgendes aus setState:

constructor(props) {
  super(props);

  this.addActiveClass= this.addActiveClass.bind(this);
  this.state = {
    isActive: false
  }
}

addActiveClass() {
  this.setState({
    isActive: true
  })
}

Verwenden this.state.isActiveSie in Ihrer Komponente , um das zu rendern, was Sie benötigen.

Dies wird komplizierter, wenn Sie den Status in Komponente 1 festlegen und in Komponente 2 verwenden möchten. Erforschen Sie einfach den unidirektionalen Datenfluss und möglicherweise den Redux, der Ihnen dabei hilft, damit umzugehen.

dhorelik
quelle
Ich verstehe, stateaber dies erklärt immer noch nicht wirklich, wie man den Klassennamen aktualisiert, wenn auf ein Element geklickt wird
Peter Flanagan
in deinem jsx markup mach - <div className={this.state.isActive ? 'active' : ''}>. Es geht um bedingtes Rendern, aber es hängt immer noch vom Zustand ab.
Dhorelik
Dadurch wird jedoch jedem Element beim Klicken die aktive Klasse hinzugefügt. Ich möchte nur, dass das angeklickte Element den activeKlassennamen hat
Peter Flanagan
2
warum jeder Artikel? Die Klasse wird dem Element hinzugefügt, für das Sie die Bedingung hinzufügen. Idealerweise sollten Ihre Elemente zur ItemKomponente abstrahiert werden. Sie werden es dann dreimal einschließen und im Grunde 3 Elemente haben, von denen jedes seinen eigenen isActiveStatus hat. Ist es was du meinst?
Dhorelik
Gibt es Itemeine Möglichkeit, dies zu tun, ohne es in eine Komponente aufzuteilen?
Peter Flanagan
2

Eine gute Probe würde helfen, die Dinge besser zu verstehen:

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; 
}

Code reagieren

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"));
Alex Jolig
quelle
2

Sie können beim Klicken eine Umschaltklasse oder einen Umschaltstatus hinzufügen

class Test extends Component(){
  state={
  active:false, 
 }
  toggleClass() {
    console.log(this.state.active)
    this.setState=({
     active:true,
   })
  }

    render() {
    <div>
      <div onClick={this.toggleClass.bind(this)}>
        <p>1</p>
      </div>
    </div>
  }

}
Rizo
quelle
2

Vielen Dank an @cssko für die richtige Antwort, aber wenn Sie es selbst versucht haben, werden Sie feststellen, dass es nicht funktioniert. Ein Vorschlag wurde von @Matei Radu gemacht, aber von @cssko abgelehnt, sodass der Code nicht ausgeführt werden kann (es wird der Fehler "Eigenschaftsbindung von undefiniert kann nicht gelesen werden" ausgegeben). Unten ist die richtige Antwort:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.addActiveClass = this.addActiveClass.bind(this);
    this.state = {
      active: false,
    };
  }
  addActiveClass() {
    const currentState = this.state.active;
    this.setState({
      active: !currentState
    });
  };

  render() {
    return ( <
      div className = {
        this.state.active ? 'your_className' : null
      }
      onClick = {
        this.addActiveClass
      } >
      <
      p > {
        this.props.text
      } < /p> < /
      div >
    )
  }
}

class Test extends React.Component {
  render() {
    return ( <
      div >
      <
      MyComponent text = {
        'Clicking this will toggle the opacity through css class'
      }
      /> < /
      div >
    );
  }
}

ReactDOM.render( <
  Test / > ,
  document.body
);
.your_className {
  opacity: 0.3
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

Samson
quelle
1

Ich habe kürzlich angefangen, React zu lernen und wollte einen Tab erstellen, um zu sehen, wie weit mein Wissen gegangen ist. Ich bin darauf gestoßen und habe beschlossen, etwas ohne Redux zu implementieren. Ich habe das Gefühl, dass die Antworten nicht widerspiegeln, was op erreichen möchte. Er möchte nur eine aktive Komponente, aber die Antworten hier setzen alle Komponenten aktiv. Ich habe es versucht.

Unten ist eine Tab-Datei

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;

Die Tabs-Datei ...

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;

Ihre Indexdatei ...

import React from 'react';
import ReactDOM from 'react-dom';
import Tabs from './components/tabs';


ReactDOM.render(
    <Tabs />
  , document.querySelector('.container'));

und die CSS

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

.active-tab {
    border-top: 1px solid red;
}

Dies ist ein Grundgerüst für etwas, das ich verbessern möchte. Wenn Sie also die tabNumber über 4 hinaus erhöhen, wird das CSS beschädigt.

J.Ewa
quelle
1

Hier ist ein Code, den ich mir ausgedacht habe:

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>
        );
    };
};
Vadim Plisko
quelle
1

React hat ein Konzept für den Komponentenstatus. Wenn Sie also umschalten möchten, verwenden Sie 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. Komponenten / 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. Ausgabe

Geben Sie hier die Bildbeschreibung ein

Rahul Shukla
quelle
0

Ich wollte nur meinen Ansatz hinzufügen. Verwenden von Hooks und Kontextanbieter.

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
}

Arbeitet schnell und ersetzt Redux.

Aaron Tomlinson
quelle