REACT - สลับคลาส onclick


93

ฉันกำลังพยายามหาวิธีสลับคลาสที่ใช้งานอยู่onClickเพื่อเปลี่ยนคุณสมบัติ CSS

ฉันได้ใช้แนวทางมากมายและอ่านคำตอบ SO มากมาย การใช้ jquery มันค่อนข้างง่ายอย่างไรก็ตามฉันคิดไม่ออกว่าจะทำเช่นนี้ด้วยการตอบสนอง รหัสของฉันอยู่ด้านล่าง ใครช่วยแนะนำว่าฉันควรทำอย่างไร

โดยไม่ต้องสร้างส่วนประกอบใหม่สำหรับแต่ละรายการสามารถทำได้หรือไม่?

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

}

คำตอบ:


86

ใช้สถานะ ปฏิกิริยาเอกสารอยู่ที่นี่

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

3
มีวิธีดำเนินการโดยไม่ต้องสร้างส่วนประกอบเพิ่มเติมหรือไม่
peter flanagan

2
คุณต้องการแยกส่วนประกอบที่ซับซ้อนออกเป็นส่วนประกอบขนาดเล็กดูที่facebook.github.io/react/docs/…
cssko

1
ฉันได้ทำลายองค์ประกอบแล้ว แต่ยังคงเพิ่มactiveให้กับแต่ละองค์ประกอบเมื่อคลิก ฉันต้องการเพียงองค์ประกอบเดียวที่จะมีคลาสที่ใช้งานอยู่
เตอร์ฟลานาแกน

1
สิ่งนี้ไม่สามารถเรียกว่าคลาส 'active' แบบสลับได้เนื่องจากคลาสแอ็คทีฟขององค์ประกอบอื่น ๆ ยังคงอยู่ที่นั่น
Dat TT

6
คุณช่วยอัปเดตคำตอบเพื่อใช้onClickแทนตัวพิมพ์เล็กทั้งหมดได้ไหมเนื่องจากคุณระบุไม่ถูกต้อง
peter flanagan

24

ฉันต้องการใช้ "&&" -operator ใน if-statement แบบอินไลน์ ในความคิดเห็นของฉันมันช่วยให้ codebase สะอาดขึ้นด้วยวิธีนี้

โดยทั่วไปคุณสามารถทำอะไรแบบนี้ได้

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

โปรดทราบว่าฟังก์ชันลูกศรคือคุณสมบัติ ES6 และอย่าลืมตั้งค่า "this.state.active" ในตัวสร้างคลาส () {}

this.state = { active: false }

หรือถ้าคุณต้องการฉีด css ใน JSX คุณสามารถทำได้ด้วยวิธีนี้

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

และคุณสามารถประกาศตัวแปร style json

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

อย่าลืมใช้ camelCase บนสไตล์ชีต JSX


2
นี่เป็นวิธีที่เนียนที่สุดในการสลับชื่อคลาสอย่างง่ายบนส่วนประกอบ
SeaWarrior404

11

addActiveClass ของคุณจำเป็นต้องรู้ว่าอะไรถูกคลิก สิ่งนี้สามารถใช้งานได้ (สังเกตว่าฉันได้เพิ่มข้อมูลที่ divs ใช้งานเป็นอาร์เรย์สถานะและตอนนี้ onClick ส่งผ่านข้อมูลที่ถูกคลิกเป็นพารามิเตอร์หลังจากนั้นสถานะจะได้รับการอัปเดตตามนั้น - มีวิธีที่ชาญฉลาดกว่าอย่างแน่นอนในการ ทำ แต่คุณได้รับความคิด)

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

9

นอกจากนี้คุณยังสามารถทำเช่นนี้กับตะขอ

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

4

ใช้ React คุณสามารถเพิ่มคลาสสลับไปยัง id / องค์ประกอบใดก็ได้ลอง

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

ฉันต้องการเพิ่มสิ่งนี้เพื่อให้คุณสามารถใช้ code-style ต่อไปนี้ได้หากคุณมีคลาสแบบคงที่ที่คุณไม่ต้องการกำหนดสำหรับแต่ละคำสั่ง "isActive":className={`left-panel ${this.state.isActive===true ? 'leftbar-open' : 'leftbar-close'}`}
Zeliax

4

React มีแนวคิดเกี่ยวกับสถานะของส่วนประกอบดังนั้นหากคุณต้องการเปลี่ยนให้ทำsetStateดังนี้

constructor(props) {
  super(props);

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

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

ในส่วนประกอบของคุณใช้this.state.isActiveเพื่อแสดงสิ่งที่คุณต้องการ

สิ่งนี้จะซับซ้อนมากขึ้นเมื่อคุณต้องการตั้งค่าสถานะในองค์ประกอบ # 1 และใช้ในองค์ประกอบ # 2 เพียงเจาะลึกมากขึ้นในการตอบสนองการไหลของข้อมูลทิศทางเดียวและอาจซ้ำซ้อนที่จะช่วยคุณจัดการกับมัน


ฉันเข้าใจstateแต่สิ่งนี้ยังอธิบายไม่ได้ว่าจะอัปเดตชื่อคลาสอย่างไรเมื่อมีการคลิกองค์ประกอบ
peter flanagan

ในของคุณมาร์กอัป JSX ทำ <div className={this.state.isActive ? 'active' : ''}>- มันเกี่ยวกับการแสดงผลตามเงื่อนไข แต่ยังต้องอาศัยสถานะ
dhorelik

แต่จะเพิ่มคลาสที่ใช้งานอยู่ในแต่ละรายการเมื่อคลิก ฉันแค่ต้องการให้รายการที่คลิกมีactiveชื่อชั้น
เตอร์ฟลานาแกน

2
ทำไมแต่ละรายการ? มันจะเพิ่มคลาสให้กับรายการที่คุณเพิ่มเงื่อนไข ตามหลักการแล้วควรแยกรายการของคุณไปยังItemส่วนประกอบ จากนั้นคุณจะรวมมัน 3 ครั้งและโดยทั่วไปจะมี 3 รายการแต่ละรายการมีisActiveสถานะของตัวเอง เป็นอย่างที่คุณหมายถึง?
dhorelik

โดยไม่แยกออกเป็นItemส่วนประกอบมีวิธีทำไหม
peter flanagan


2

ตัวอย่างที่ดีจะช่วยให้เข้าใจสิ่งต่างๆได้ดีขึ้น:

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

รหัสตอบสนอง

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

2

คุณสามารถเพิ่มคลาสสลับหรือสลับสถานะเมื่อคลิก

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

}

2

ขอบคุณ @cssko ที่ให้คำตอบที่ถูกต้อง แต่ถ้าคุณลองด้วยตัวเองคุณจะรู้ว่ามันไม่ได้ผล มีการเสนอข้อเสนอแนะโดย @Matei Radu แต่ถูกปฏิเสธโดย @cssko ดังนั้นรหัสจึงไม่สามารถรันได้ (จะทำให้เกิดข้อผิดพลาด 'ไม่สามารถอ่านการผูกคุณสมบัติของไม่ได้กำหนด') ด้านล่างนี้คือคำตอบที่ถูกต้องในการทำงาน:

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>


1

ฉันเริ่มเรียนรู้ React เมื่อเร็ว ๆ นี้และต้องการสร้างแท็บเพื่อดูว่าความรู้ของฉันไปไกลแค่ไหน ฉันเจอสิ่งนี้และตัดสินใจที่จะใช้บางสิ่งบางอย่างโดยไม่ซ้ำ ฉันรู้สึกว่าคำตอบไม่ได้สะท้อนถึงสิ่งที่หน่วยงานต้องการบรรลุ เขาต้องการส่วนประกอบที่ใช้งานเพียงชิ้นเดียว แต่คำตอบที่นี่จะตั้งค่าให้ส่วนประกอบทั้งหมดทำงาน ฉันให้มันยิง

ด้านล่างเป็นไฟล์แท็บ

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;

ไฟล์แท็บ ...

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;

ไฟล์ดัชนีของคุณ ...

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


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

และ css

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

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

นี่เป็นโครงกระดูกของบางสิ่งที่ฉันต้องการปรับปรุงดังนั้นการเพิ่ม tabNumber เกิน 4 จะทำให้ css เสียหาย


1

นี่คือรหัสที่ฉันคิดขึ้นมา:

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

1

React มีแนวคิดเกี่ยวกับสถานะขององค์ประกอบดังนั้นหากคุณต้องการ Toggle ให้ใช้ 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. ส่วนประกอบ / 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. เอาต์พุต

ป้อนคำอธิบายภาพที่นี่


0

แค่อยากจะเพิ่มแนวทางของฉัน การใช้ hooks และผู้ให้บริการบริบท

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
}

ทำงานได้เร็วและแทนที่ redux

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.