Estoy tratando de averiguar cómo alternar una clase activa onClick
para cambiar las propiedades de CSS.
He adoptado muchos enfoques y leído muchas respuestas SO. Usar jquery sería relativamente simple, sin embargo, no puedo hacer esto con react. Mi código está debajo. ¿Alguien puede aconsejarme cómo debo hacer esto?
Sin crear un nuevo componente para cada artículo, ¿es posible hacer esto?
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>
}
}
javascript
reactjs
peter flanagan
fuente
fuente
active
a cada elemento al hacer clic. Solo quiero que un elemento tenga una clase activaonClick
en lugar de todas las minúsculas, ya que lo hizo incorrectamentePreferiría usar el operador "&&" en la instrucción if en línea. En mi opinión, proporciona una base de código más limpia de esta manera.
Generalmente podrías estar haciendo algo como esto
render(){ return( <div> <button className={this.state.active && 'active'} onClick={ () => this.setState({active: !this.state.active}) }>Click me</button> </div> ) }
Solo tenga en cuenta que la función de flecha es la característica ES6 y recuerde establecer el valor 'this.state.active' en la clase constructor () {}
this.state = { active: false }
o si desea inyectar css en JSX, puede hacerlo de esta manera
<button style={this.state.active && style.button} >button</button>
y puedes declarar la variable json de estilo
const style = { button: { background:'red' } }
recuerde usar camelCase en hojas de estilo JSX.
fuente
Bueno, su addActiveClass necesita saber en qué se hizo clic. Algo como esto podría funcionar (observe que agregué la información sobre qué divs están activos como una matriz de estado, y que onClick ahora pasa la información en la que se hizo clic como parámetro, después de lo cual el estado se actualiza en consecuencia; ciertamente hay formas más inteligentes de hazlo, pero entiendes la idea).
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> ); } }
fuente
También puede hacer esto con ganchos .
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> ); }
fuente
usando React puedes agregar una clase de alternancia a cualquier id / elemento, prueba
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> ) } ......
fuente
className={`left-panel ${this.state.isActive===true ? 'leftbar-open' : 'leftbar-close'}`}
React tiene un concepto de estado de los componentes, por lo que si desea cambiarlo, haga lo siguiente
setState
:constructor(props) { super(props); this.addActiveClass= this.addActiveClass.bind(this); this.state = { isActive: false } } addActiveClass() { this.setState({ isActive: true }) }
En su componente, use
this.state.isActive
para renderizar lo que necesita.Esto se vuelve más complicado cuando desea establecer el estado en el componente n. ° 1 y usarlo en el componente n. ° 2. Simplemente profundice más en el flujo de datos unidireccional de reacción y posiblemente redux que lo ayudará a manejarlo.
fuente
state
pero esto todavía no explica realmente cómo actualizar el nombre de la clase cuando se hace clic en un elemento<div className={this.state.isActive ? 'active' : ''}>
. Se trata de una representación condicional, pero aún depende del estado.active
Item
componente. Luego, lo incluirá 3 veces y básicamente tendrá 3 elementos, cada uno con su propioisActive
estado. ¿Es eso lo que quieres decir?Item
componente, ¿hay alguna manera de hacer esto?Las respuestas anteriores funcionarán, pero en caso de que desee un enfoque diferente, pruebe classname: https://github.com/JedWatson/classnames
fuente
Una buena muestra ayudaría a comprender mejor las cosas:
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; }
Reaccionar código
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"));
fuente
puede agregar alternar clase o alternar estado al hacer clic
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> } }
fuente
Gracias a @cssko por proporcionar la respuesta correcta, pero si lo probó usted mismo se dará cuenta de que no funciona. @Matei Radu ha hecho una sugerencia, pero fue rechazada por @cssko, por lo que el código no se puede ejecutar (arrojará el error 'No se puede leer el enlace de propiedad de indefinido'). A continuación se muestra la respuesta correcta de trabajo:
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>
fuente
Comencé a aprender React recientemente y quería crear una pestaña solo para ver qué tan lejos ha llegado mi conocimiento. Me encontré con esto y decidí implementar algo sin redux. Siento que las respuestas no reflejan lo que op quiere lograr. Solo quiere un componente activo, pero las respuestas aquí activarán todos los componentes. Le he dado una oportunidad.
A continuación se muestra un archivo de pestaña
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;
El archivo de pestañas ...
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;
su archivo de índice ...
import React from 'react'; import ReactDOM from 'react-dom'; import Tabs from './components/tabs'; ReactDOM.render( <Tabs /> , document.querySelector('.container'));
y el css
.tab-bar { margin: 10px 10px; border: 1px solid grey; } .active-tab { border-top: 1px solid red; }
Este es un esqueleto de algo que quiero mejorar, por lo que aumentar el tabNumber más allá de 4 romperá el CSS.
fuente
Aquí hay un código que se me ocurrió:
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> ); }; };
fuente
React tiene un concepto de estado de los componentes, por lo que si desea alternar, use setState:
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;
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;
fuente
Solo quería agregar mi enfoque. Utilizando ganchos y proveedor de contexto.
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 }
Funciona rápido y reemplaza redux.
fuente