70

I need to add the class active after clicking on the button and remove all other active classes.

Look here please: https://codepen.io/azat-io/pen/RWjyZX

var Tags = React.createClass({
  setFilter: function(filter) {
    this.props.onChangeFilter(filter);
  },
  render: function() {
    return <div className="tags">
      <button className="btn active" onClick={this.setFilter.bind(this, '')}>All</button>
      <button className="btn" onClick={this.setFilter.bind(this, 'male')}>male</button>
      <button className="btn" onClick={this.setFilter.bind(this, 'female')}>female</button>
      <button className="btn" onClick={this.setFilter.bind(this, 'child')}>child</button>
      <button className="btn" onClick={this.setFilter.bind(this, 'blonde')}>blonde</button>
     </div>
  }
});

var Kid = React.createClass({
  render: function() {
    return <ul>
      <li>{this.props.name}</li>
      </ul>
  }
});

var List = React.createClass({
  getInitialState: function() {
    return {
      filter: ''
    };
  },
  changeFilter: function(filter) {
    this.setState({
      filter: filter
    });
  },
  render: function() {
    var list = this.props.Data;
    
    if (this.state.filter !== '') {
      list = list.filter((i)=> i.tags.indexOf(this.state.filter) !== -1);
      console.log(list);
    } 
    
    list = list.map(function(Props){
      return <Kid {...Props} />
    });

    return <div>
      <h2>Kids Finder</h2>
      <Tags onChangeFilter={this.changeFilter}/>
      {list}
    </div>
  }
});

var options = {
  Data:  [{
    name: 'Eric Cartman',
    tags: ['male', 'child']
  },{
    name: 'Wendy Testaburger',
    tags: ['female', 'child']
  },{
    name: 'Randy Marsh',
    tags: ['male']
  },{
    name: 'Butters Stotch',
    tags: ['male', 'blonde', 'child']
  },{
    name: 'Bebe Stevens',
    tags: ['female', 'blonde', 'child']
  }]
};

var element = React.createElement(List, options);
React.render(element, document.body);

How do I make it better?

3
  • I would suggest making a "button" component rather than just rendering a bunch of links under your "Tags" component. Then for each button you can conditionally set the className attribute conditionally. This might help: github.com/JedWatson/classnames Commented Oct 21, 2015 at 15:07
  • 1
    @JohnGibbons, I don't want add any other utilities. I think it's simple thing. Update codepen project with <buttons>. Commented Oct 21, 2015 at 15:15
  • Remember which button was clicked in the component's state. Commented Oct 21, 2015 at 15:18

6 Answers 6

47

It is simple. take a look at this

https://codepen.io/anon/pen/mepogj?editors=001

basically you want to deal with states of your component so you check the currently active one. you will need to include

getInitialState: function(){}
//and 
isActive: function(){}

check out the code on the link

Sign up to request clarification or add additional context in comments.

4 Comments

The best solution i've ever seen. Congrats!
Is there more detailed instructions for this? I have a hard time wrapping my head around that example.
Hi, im trying to do the same thing but using redux. The problem is that my isActive() method is not triggered when the this.props changes. Any help? Ty
isActive method will fire every time the component renders. and that happens every time the properties change, in your case since you are using redux, what might be happening is that your tree is not immutable and hence does not re renders the components because it does not detect a state change.
26

this is pretty useful:

https://github.com/JedWatson/classnames

You can do stuff like

classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'

// lots of arguments of various types
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'

// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'

or use it like this

var btnClass = classNames('btn', this.props.className, {
  'btn-pressed': this.state.isPressed,
  'btn-over': !this.state.isPressed && this.state.isHovered
});

1 Comment

This repo is also mention on react's web site: reactjs.org/docs/faq-styling.html
8

Taken from their site.

render() {
  let className = 'menu';
  if (this.props.isActive) {
    className += ' menu-active';
  }
  return <span className={className}>Menu</span>
}

https://reactjs.org/docs/faq-styling.html

Comments

5

Since you already have <Tags> component calling a function on its parent, you do not need additional state: simply pass the filter to the <Tags> component as a prop, and use this in rendering your buttons. Like so:

Change your render function inside your <Tags> component to:

render: function() {
  return <div className = "tags">
    <button className = {this._checkActiveBtn('')} onClick = {this.setFilter.bind(this, '')}>All</button>
    <button className = {this._checkActiveBtn('male')} onClick = {this.setFilter.bind(this, 'male')}>male</button>
    <button className = {this._checkActiveBtn('female')} onClick = {this.setFilter.bind(this, 'female')}>female</button>
    <button className = {this._checkActiveBtn('blonde')} onClick = {this.setFilter.bind(this, 'blonde')}>blonde</button>
  </div>
},

And add a function inside <Tags>:

_checkActiveBtn: function(filterName) {
  return (filterName == this.props.activeFilter) ? "btn active" : "btn";
}

And inside your <List> component, pass the filter state to the <tags> component as a prop:

return <div>
  <h2>Kids Finder</h2> 
  <Tags filter = {this.state.filter} onChangeFilter = {this.changeFilter} />
  {list}
</div>

Then it should work as intended. Codepen here (hope the link works)

Comments

3

you can also use pure js to accomplish this like the old ways with jquery

try this if you want a simple way

warning: this may not be the correct way to do it in react.

 document.getElementById("myID").classList.add("show-example");

4 Comments

While this may technically work, it is going to be very tricky to read code like this.
not really, I just tried to give an alternative solution that works. thanks for the comment anyways.
Unless using it inside a hook properly, this may not match with virtual DOM which can introduce bugs in the application.
This is not the way to do it in react and should not be considered a solution
-1
const activeState = (e)=>{
    var id = e.target.id
    const idArray = ["homeBtn","aboutBtn","servicesBtn","portfolioBtn","testmBtn","blogBtn","contactBtn"]

    idArray.forEach((element)=> {
        document.getElementById(element).classList.remove("active")
    });
    console.log(id);
    document.getElementById(id).classList.add("active")

}

2 Comments

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
Don't use manual DOM manipulation in react

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.