REACT - beralih kelas onclick

93

Saya mencoba mencari cara untuk mengaktifkan kelas aktif onClickuntuk mengubah properti CSS.

Saya telah mengambil banyak pendekatan, dan membaca banyak jawaban SO. Menggunakan jquery itu akan relatif sederhana, namun, saya tidak tahu melakukan ini dengan react. Kode saya ada di bawah. Adakah yang bisa memberi tahu bagaimana saya harus melakukan ini?

Tanpa membuat komponen baru untuk setiap item, apakah mungkin melakukan ini?

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
sumber

Jawaban:

86

Gunakan negara bagian. Dokumen Reacts ada di sini .

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.dll
sumber
3
apakah ada cara untuk melakukan ini tanpa membuat komponen tambahan?
peter flanagan
2
Anda ingin memecah komponen kompleks menjadi beberapa komponen yang lebih kecil lihat facebook.github.io/react/docs/…
cssko
1
Saya telah memecah komponen, tetapi ini masih menambah activesetiap elemen saat diklik. Saya hanya ingin satu elemen memiliki kelas yang aktif
peter flanagan
1
Ini tidak bisa disebut kelas 'aktif' yang diubah karena kelas aktif elemen lain masih ada.
Dat TT
6
dapatkah Anda memperbarui jawaban untuk digunakan onClicksebagai lawan dari semua huruf kecil karena Anda salah
peter flanagan
24

Saya lebih suka menggunakan "&&" -operator pada pernyataan-if sebaris. Menurut pendapat saya, cara ini memberikan basis kode yang lebih bersih.

Biasanya Anda bisa melakukan hal seperti ini

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

Ingatlah bahwa fungsi panah adalah fitur ES6 dan ingat untuk menyetel nilai 'this.state.active' di class constructor () {}

this.state = { active: false }

atau jika Anda ingin menginjeksi css di JSX, Anda bisa melakukannya dengan cara ini

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

dan Anda dapat mendeklarasikan variabel style json

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

ingat menggunakan camelCase di stylesheet JSX.

Jimi Pajala
sumber
2
Ini adalah cara paling apik untuk mengubah nama kelas sederhana pada komponen.
SeaWarrior404
11

Nah, addActiveClass Anda perlu tahu apa yang diklik. Sesuatu seperti ini dapat berfungsi (perhatikan bahwa saya telah menambahkan informasi div mana yang aktif sebagai larik status, dan bahwa onClick sekarang meneruskan informasi apa yang diklik sebagai parameter setelah status diperbarui dengan semestinya - tentu ada cara yang lebih cerdas untuk lakukan, tetapi Anda mendapatkan idenya).

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ć
sumber
9

Anda juga bisa melakukan ini dengan pengait .

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

sumber
4

menggunakan React Anda dapat menambahkan kelas toggle ke id / elemen apapun, coba

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
sumber
Saya ingin menambahkan bahwa Anda dapat menggunakan gaya kode berikut jika Anda memiliki kelas statis yang tidak ingin Anda definisikan untuk setiap pernyataan "isActive":className={`left-panel ${this.state.isActive===true ? 'leftbar-open' : 'leftbar-close'}`}
Zeliax
4

React memiliki konsep status komponen, jadi jika Anda ingin mengubahnya, lakukan setState:

constructor(props) {
  super(props);

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

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

Dalam komponen Anda gunakan this.state.isActiveuntuk membuat apa yang Anda butuhkan.

Ini menjadi lebih rumit ketika Anda ingin menyetel status di komponen # 1 dan menggunakannya di komponen # 2. Gali lebih banyak lagi untuk bereaksi aliran data searah dan mungkin reduksi yang akan membantu Anda menanganinya.

dhorelik
sumber
Saya mengerti statetetapi ini masih belum benar-benar menjelaskan cara memperbarui nama kelas ketika sebuah elemen diklik
peter flanagan
di markup jsx Anda lakukan - <div className={this.state.isActive ? 'active' : ''}>. Ini tentang rendering bersyarat, tetapi masih bergantung pada status.
dhorelik
tetapi itu akan menambahkan kelas aktif ke setiap item saat diklik. Saya hanya ingin item yang diklik memiliki activenama kelas
peter flanagan
2
mengapa setiap item? Ini akan menambahkan kelas ke item yang Anda tambahkan kondisinya. Idealnya barang Anda harus diabstraksi ke Itemkomponen. Anda kemudian akan memasukkannya 3 kali dan pada dasarnya akan memiliki 3 item, masing-masing memiliki statusnya sendiri isActive. Apa yang kamu maksud
dhorelik
tanpa membaginya menjadi Itemkomponen, apakah ada cara untuk melakukan ini?
peter flanagan
2

Sampel yang baik akan membantu memahami berbagai hal dengan lebih baik:

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

Kode React

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
sumber
2

Anda dapat menambahkan kelas sakelar atau status sakelar saat diklik

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
sumber
2

Terima kasih kepada @cssko untuk memberikan jawaban yang benar, tetapi jika Anda mencobanya sendiri, Anda akan menyadari bahwa itu tidak berhasil. Sebuah saran telah dibuat oleh @Matei Radu, tetapi ditolak oleh @cssko, sehingga kode tetap tidak dapat dijelajahi (ini akan memunculkan kesalahan 'Tidak dapat membaca ikatan properti tidak terdefinisi'). Di bawah ini adalah jawaban yang benar:

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>

Simson
sumber
1

Saya mulai belajar React baru-baru ini dan ingin membuat tab hanya untuk melihat sejauh mana pengetahuan saya telah berkembang. Saya menemukan ini dan memutuskan untuk menerapkan sesuatu tanpa redux. Saya merasa jawabannya tidak mencerminkan apa yang ingin dicapai oleh operasi. Dia ingin hanya satu komponen aktif tetapi jawaban di sini akan membuat semua komponen aktif. Saya telah mencobanya.

Di bawah ini adalah file tab

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;

File tab ...

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;

file indeks Anda ...

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


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

dan css

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

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

Ini adalah kerangka dari sesuatu yang ingin saya tingkatkan sehingga meningkatkan tabNumber melebihi 4 akan merusak css.

J.Ewa
sumber
1

Ini adalah kode yang saya buat:

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
sumber
1

React memiliki konsep status komponen, jadi jika Anda ingin beralih, gunakan 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. komponen / 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. Keluaran

masukkan deskripsi gambar di sini

Rahul Shukla
sumber
0

Hanya ingin menambahkan pendekatan saya. Menggunakan hook dan penyedia konteks.

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
}

Bekerja cepat, dan menggantikan redux.

Aaron Tomlinson
sumber