1

I'm trying to test a functionality out where if you have a list of li with an attribute of aria-checked, clicking on one will toggle it to true, while turning the rest of the li's aria to false.

I have implemented it below:

class Parent extends React.Component {
  constructor(props){
    super(props);
    this.state = {checked: false, items:[]}
    this.clicky = this.clicky.bind(this);
  }

  clicky(e){
     this.setState({
       items: [...this.state.items, e.currentTarget]
     }, () => {
       this.state.items.map((item, index) => {
          if(index == this.state.items.length - 1){
            item.setAttribute("aria-checked", "true");
          }
          else{
            item.setAttribute("aria-checked","false");
          }
       })
     })
  }

  render() {
    return (
      <ul>
        <li
          aria-checked={this.state.checked}
          onClick={this.clicky}>item 1</li>
        <li 
          aria-checked={this.state.checked}
          onClick={this.clicky}>item 2</li>
        <li 
          aria-checked={this.state.checked}
          onClick={this.clicky}>item 3</li>
      </ul>
    )
  }
}

React.render(<Parent />, document.getElementById('app'));

So on click, the clicked item's aria will become true, while all the other once will turn false. I'm wondering if there is a better/more efficient way of getting the same result. Thanks.

Working version: https://codepen.io/anon/pen/QmeKEw?editors=0010

Nah
  • 1,690
  • 2
  • 26
  • 46
blankface
  • 5,757
  • 19
  • 67
  • 114
  • 1
    I wonder how you are using `item.setAttribute()` in your React code. Is this function defined? – Nah Apr 16 '18 at 09:36
  • its defined https://www.w3schools.com/jsref/met_element_setattribute.asp – blankface Apr 16 '18 at 09:48
  • 1
    Dear, you are coding in React which only deals with Virtual DOM unless or unless you create a reference to real DOM and use that in your code. It is not normal DOM Javascript. React code logic and domain is slight different. – Nah Apr 16 '18 at 09:53
  • i understand. but my code seems to run as expected. are there any pitfalls i should be aware of? – blankface Apr 16 '18 at 10:17
  • Yes. `setAttribute()` is `imperative`. [Good `ReactJS` is `declarative`](https://stackoverflow.com/a/33656983/5566355) @ZeroDarkThirty – Arman Charan Apr 16 '18 at 10:48

2 Answers2

1

See Intro To React for more info.

// App.
class App extends React.Component {

  // State.
  state = {
    checked: false,
    items: [1, 2, 3]
  }

  // Render.
  render = () => (
    <ul>
      {this.state.items.map(item => (
        <li aria-checked={this.state.checked == item} onClick={() => this.clicky(item)}>
          Item {item}
        </li>
      ))}
    </ul>
  )
  
  // Clicky
  clicky = item => console.log('Clicked:', item) || this.setState({checked: item})
  
}

ReactDOM.render(<App/>, document.querySelector('#root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Arman Charan
  • 5,669
  • 2
  • 22
  • 32
0

You can play around with indexes, set up you checkedIndex state key, and compare index of each item with state.checkedIndex:

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { checkedIndex: -1 };
  }

 render() {
    const items = [ 'item 1', 'item 2', 'item 3' ];
    return (
      <ul>
        {items.map((item, index) =>
          <li
            key={item}
            aria-checked={this.checkedIndex === index}
            onClick={() => this.setState({ checkedIndex: index })}
          >
            item 1
          </li>)}
      </ul>
    )
  }
}

React.render(<Parent/>, document.getElementById('app'));
Artem Mirchenko
  • 2,140
  • 1
  • 9
  • 21