REACT - bật tắt lớp


93

Tôi đang cố gắng tìm cách chuyển đổi một lớp đang hoạt động onClickđể thay đổi các thuộc tính CSS.

Tôi đã thực hiện nhiều cách tiếp cận và đọc nhiều câu trả lời SO. Sử dụng jquery nó sẽ tương đối đơn giản, tuy nhiên, tôi không thể tìm ra cách làm điều này với react. Mã của tôi ở dưới đây. Bất cứ ai có thể tư vấn làm thế nào tôi nên làm điều này?

Nếu không tạo một thành phần mới cho mỗi mục, liệu có thể làm được điều này không?

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

}

Câu trả lời:


86

Sử dụng trạng thái. Tài liệu về React có ở đây .

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
có cách nào để làm điều này mà không cần tạo thêm một thành phần không?
peter flanagan

2
Bạn muốn phá vỡ các thành phần phức tạp thành các thành phần nhỏ hơn thấy facebook.github.io/react/docs/...
cssko

1
Tôi đã chia nhỏ thành phần, nhưng điều này vẫn thêm activevào từng phần tử khi nhấp chuột. Tôi chỉ muốn một yếu tố để có một lớp học tích cực
peter Flanagan

1
Đây không thể được gọi là lớp 'hoạt động' đã chuyển đổi vì các lớp hoạt động của các phần tử khác vẫn ở đó.
Dat TT

6
bạn có thể vui lòng cập nhật câu trả lời cho sử dụng onClicknhư trái ngược với tất cả chữ thường là bạn có sai
peter Flanagan

24

Tôi thích sử dụng "&&" -operator trên câu lệnh if nội tuyến. Trong opinnion của tôi, nó cung cấp cơ sở mã sạch hơn theo cách này.

Nói chung bạn có thể đang làm một cái gì đó như thế này

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

Chỉ cần lưu ý hàm arrow là tính năng của ES6 và hãy nhớ đặt giá trị 'this.state.active' trong hàm tạo lớp () {}

this.state = { active: false }

hoặc nếu bạn muốn đưa css vào JSX, bạn có thể thực hiện theo cách này

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

và bạn có thể khai báo biến style json

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

hãy nhớ sử dụng camelCase trên các bảng định kiểu JSX.


2
Đây là cách khéo léo nhất để chuyển đổi các tên lớp đơn giản trên các thành phần.
SeaWarrior404

11

Vâng, addActiveClass của bạn cần biết những gì đã được nhấp vào. Một cái gì đó như thế này có thể hoạt động (lưu ý rằng tôi đã thêm thông tin mà div đang hoạt động dưới dạng mảng trạng thái và onClick bây giờ chuyển thông tin những gì được nhấp vào dưới dạng tham số sau đó trạng thái được cập nhật tương ứng - chắc chắn có nhiều cách thông minh hơn để làm điều đó, nhưng bạn có được ý tưởng).

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

Bạn cũng có thể làm điều này với móc .

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

bằng cách sử dụng React, bạn có thể thêm lớp chuyển đổi vào bất kỳ id / phần tử nào, hãy thử

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

Tôi muốn thêm vào điều này rằng bạn có thể sử dụng kiểu mã sau nếu bạn có một lớp tĩnh mà bạn không muốn xác định cho mỗi câu lệnh "isActive":className={`left-panel ${this.state.isActive===true ? 'leftbar-open' : 'leftbar-close'}`}
Zeliax

4

React có một khái niệm về trạng thái các thành phần, vì vậy nếu bạn muốn chuyển đổi nó, hãy thực hiện setState:

constructor(props) {
  super(props);

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

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

Trong thành phần của bạn sử dụng this.state.isActiveđể hiển thị những gì bạn cần.

Điều này trở nên phức tạp hơn khi bạn muốn thiết lập trạng thái trong thành phần số 1 và sử dụng nó trong thành phần số 2. Chỉ cần tìm hiểu sâu hơn về phản ứng luồng dữ liệu một chiều và có thể là dòng dữ liệu sẽ giúp bạn xử lý nó.


Tôi hiểu statenhưng điều này vẫn doesnt thực sự giải thích làm thế nào để cập nhật các classname khi một phần tử được nhấp
peter Flanagan

trong đánh dấu jsx của bạn làm - <div className={this.state.isActive ? 'active' : ''}>. Đó là về kết xuất có điều kiện, nhưng vẫn dựa vào trạng thái.
dhorelik

nhưng điều đó sẽ thêm lớp đang hoạt động vào từng mục khi nhấp chuột. Tôi chỉ muốn mục nhấp vào để có activetên lớp
peter Flanagan

2
tại sao mỗi mục? Nó sẽ thêm lớp vào mục mà bạn thêm điều kiện. Lý tưởng nhất là các mục của bạn nên được trừu tượng hóa Itemthành thành phần. Sau đó, bạn sẽ gộp nó 3 lần và về cơ bản sẽ có 3 mục, mỗi mục có isActivetrạng thái riêng . Ý bạn là gì?
dhorelik

mà không cần tách nó ra thành một Itemthành phần có cách nào để làm điều này không?
peter flanagan


2

Một mẫu tốt sẽ giúp hiểu rõ hơn mọi thứ:

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

Mã phản ứng

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

bạn có thể thêm lớp chuyển đổi hoặc trạng thái chuyển đổi khi nhấp vào

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

Cảm ơn @cssko đã cung cấp câu trả lời chính xác, nhưng nếu bạn tự mình thử, bạn sẽ nhận ra nó không hoạt động. Một đề xuất đã được đưa ra bởi @Matei Radu, nhưng đã bị @cssko từ chối, vì vậy mã vẫn không thể chạy được (nó sẽ gây ra lỗi 'Không thể đọc ràng buộc thuộc tính của không xác định'). Dưới đây là câu trả lời chính xác:

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

Tôi bắt đầu học React gần đây và muốn xây dựng một tab chỉ để xem kiến ​​thức của tôi đã đi được bao xa. Tôi đã xem qua điều này và quyết định thực hiện một cái gì đó mà không có redux. Tôi cảm thấy câu trả lời không phản ánh những gì op muốn đạt được. Anh ta chỉ muốn một thành phần hoạt động nhưng câu trả lời ở đây sẽ đặt tất cả các thành phần hoạt động. Tôi đã cho nó một shot.

Dưới đây là một tệp 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;

Tệp 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;

tệp chỉ mục của bạn ...

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


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

và css

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

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

Đây là khung của một số thứ tôi muốn cải thiện, vì vậy việc tăng tabNumber vượt quá 4 sẽ phá vỡ css.


1

Đây là mã tôi đã nghĩ ra:

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 có một khái niệm về trạng thái các thành phần, vì vậy nếu bạn muốn Toggle, hãy sử dụng 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. thành phần / 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. Đầu ra

nhập mô tả hình ảnh ở đây


0

Chỉ muốn thêm cách tiếp cận của tôi. Sử dụng hook và trình cung cấp ngữ cảnh.

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
}

Hoạt động nhanh và thay thế redux.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.