Estou tentando descobrir como alternar uma classe ativa onClick
para alterar as propriedades CSS.
Eu fiz muitas abordagens e li muitas respostas de SO. Usar jquery seria relativamente simples, no entanto, não consigo descobrir como fazer isso com o react. Meu código está abaixo. Alguém pode aconselhar como devo fazer isso?
Sem criar um novo componente para cada item, é possível fazer isso?
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
fonte
fonte
active
a cada elemento no clique. Eu só quero que um elemento tenha uma classe ativaonClick
em vez de todas as letras minúsculas, já que você usou incorretamenteEu preferiria usar o operador "&&" na instrução if embutida. Na minha opinião, ele fornece uma base de código mais limpa dessa forma.
Geralmente você poderia estar fazendo algo assim
render(){ return( <div> <button className={this.state.active && 'active'} onClick={ () => this.setState({active: !this.state.active}) }>Click me</button> </div> ) }
Apenas tenha em mente que a função de seta é um recurso ES6 e lembre-se de definir o valor 'this.state.active' no construtor de classe () {}
this.state = { active: false }
ou se você deseja injetar css em JSX você pode fazer desta forma
<button style={this.state.active && style.button} >button</button>
e você pode declarar a variável json de estilo
const style = { button: { background:'red' } }
lembre-se de usar camelCase em folhas de estilo JSX.
fonte
Bem, seu addActiveClass precisa saber o que foi clicado. Algo como isso pode funcionar (observe que adicionei as informações de quais divs estão ativos como uma matriz de estado, e que onClick agora passa a informação que foi clicado como um parâmetro após o qual o estado é devidamente atualizado - certamente existem maneiras mais inteligentes de faça, mas essa é a ideia).
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> ); } }
fonte
Você também pode fazer isso com 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> ); }
fonte
usando React, você pode adicionar classe de alternância a qualquer id / elemento, tente
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> ) } ......
fonte
className={`left-panel ${this.state.isActive===true ? 'leftbar-open' : 'leftbar-close'}`}
O React tem um conceito de estado de componentes, então se você quiser trocá-lo, faça
setState
:constructor(props) { super(props); this.addActiveClass= this.addActiveClass.bind(this); this.state = { isActive: false } } addActiveClass() { this.setState({ isActive: true }) }
Em seu componente, use
this.state.isActive
para renderizar o que você precisa.Isso fica mais complicado quando você deseja definir o estado no componente # 1 e usá-lo no componente # 2. Basta pesquisar mais no fluxo de dados unidirecional de reação e possivelmente reduxar para ajudá-lo a lidar com isso.
fonte
state
mas isso ainda não explica realmente como atualizar o nome da classe quando um elemento é clicado<div className={this.state.isActive ? 'active' : ''}>
. É sobre renderização condicional, mas ainda depende de estado.active
nome da turmaItem
componente. Você o incluirá 3 vezes e terá basicamente 3 itens, cada um com seu próprioisActive
estado. É isso que você quer dizer?Item
componente, há uma maneira de fazer isso?As respostas acima funcionarão, mas caso você queira uma abordagem diferente, tente classname: https://github.com/JedWatson/classnames
fonte
Um bom exemplo ajudaria a entender melhor as coisas:
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; }
Código de reação
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"));
fonte
você pode adicionar classe de alternância ou estado de alternância ao clicar
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> } }
fonte
Obrigado a @cssko por fornecer a resposta correta, mas se você mesmo tentou, perceberá que não funciona. Uma sugestão foi feita por @Matei Radu, mas foi rejeitada por @cssko, então o código permanece impossível de executar (ele gerará o erro 'Não é possível ler vínculo de propriedade de indefinido'). Abaixo está a resposta correta de trabalho:
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>
fonte
Comecei a aprender React recentemente e queria criar uma guia apenas para ver o quão longe meu conhecimento foi. Me deparei com isso e decidi implementar algo sem redux. Eu meio que sinto que as respostas não refletem o que op quer alcançar. Ele deseja apenas um componente ativo, mas as respostas aqui definirão todos os componentes ativos. Eu dei uma chance.
Abaixo está um arquivo de guia
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;
O arquivo de guias ...
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;
seu arquivo de índice ...
import React from 'react'; import ReactDOM from 'react-dom'; import Tabs from './components/tabs'; ReactDOM.render( <Tabs /> , document.querySelector('.container'));
e o css
.tab-bar { margin: 10px 10px; border: 1px solid grey; } .active-tab { border-top: 1px solid red; }
Este é o esqueleto de algo que desejo melhorar, então aumentar o tabNumber além de 4 quebrará o css.
fonte
Aqui está um código que criei:
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> ); }; };
fonte
O React tem um conceito de estado dos componentes, então se você quiser 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;
fonte
Só queria adicionar minha abordagem. Usando ganchos e provedor 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 e substitui redux.
fonte