Reactjs Toggle onClick variable

Asked

Viewed 167 times

2

I’m trying to come up with a logic of a toggle, which activates/disables a kind of filter, but now I need to implement a new functionality in it, it works like this, if I click on a category button, it makes a request, switches to on (which causes some items to be rendered in my other component, step via context api), if I click dnv, it switches to off and the rendering goes back to what it was before, the problem is, I need to implement it to work with more than one category button, that is, if I click on a category (it stays on) and click on another category (it changes to off), which actually should not occur.

    function toggleFunc(serviceEndpoint, category) {
      onClickCategoryFetch(serviceEndpoint, category);
      setToggle((prevToggle) => !prevToggle);
    }

    return Object.values(typeCategory)
      .slice(0, FIRST_FIVE_CATEGORY)
      .map((category) => (
        <button
          type="button"
          key={ `${category.strCategory}` }
          data-testid={ `${category.strCategory}-category-filter` }
          onClick={ () => toggleFunc(endpoint, category.strCategory) }
        >
          {category.strCategory}
        </button>
      ));
  }

2 answers

2

When working with several states and several <button/> Each button has to have its own state, so that it has its own control and does not clash with the other states. It can be done in several ways, for example create a state for each <button/> or else an object with states (I recommend this one) so with this I will represent in a minimum example these words and try to give a plausible north so that I can understand the logic:

Component:

class App extends React.Component {
    state = {
      buttons: [{
        id: 1,
        name: "Button 1",
        isStatus: false
      },{
        id: 2,
        name: "Button 2",
        isStatus: true
      },{
        id: 3,
        name: "Button 3",
        isStatus: false
      }]
    }    
    constructor() {
      super();
      this.onClickChangeStatus = 
        this.onClickChangeStatus.bind(this);
    }
    onClickChangeStatus(id) {
      const buttons = this
        .state
        .buttons
        .map(x => {
          if (x.id === id) {
            x.isStatus = !x.isStatus;
          }
          return x;
        }); 
        this.setState({buttons});
    }
    render() {
      const { buttons } = this.state; 
      return (
        <div>
        {buttons.map((e,i) => (
          <div style={{padding: 10}}>
            <button onClick={x => this.onClickChangeStatus(e.id)}>
              {e.name}
            </button>
            <span style={{padding: 10}}>
              {e.isStatus? "On": "Off" }
            </span>
          </div>
        ))}
        </div>
      )
    }
}

ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root">Carregando ...</div>


Function:

function App() {
  const [buttons, setButtons] = React.useState([
      {
        id: 1,
        name: "Button 1",
        isStatus: false
      },{
        id: 2,
        name: "Button 2",
        isStatus: true
      },{
        id: 3,
        name: "Button 3",
        isStatus: false
      }]
    );
   
    function onClickChangeStatus(id) {
      const c = buttons.map(c => {
        if (c.id === id){
          c.isStatus = !c.isStatus;
        }
        return c;
      });
      setButtons(c);
    }    
    
    return (
      <div>
      {buttons.map((e,i) => (
        <div style={{padding: 10}}>
          <button onClick={x => onClickChangeStatus(e.id)}>
            {e.name}
          </button>
          <span style={{padding: 10}}>
            {e.isStatus? "On": "Off"}
          </span>
        </div>
      ))}
      </div>      
    )
}

ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<div id="root">Carregando ...</div>

  • Thank you so much for the help, I liked the abstraction, can solve in a very good way!

0


For consultation of people with a similar problem, I solved as follows:

In the previous I created a toggle

 const [toggle, setToggle] = useState(false);

In the component, I created a state to store the category, retrieved that category in the button value and sent it to the function

const [selectedCategory, setSelectedCategory] = useState('all');

   <button
     type="button"
     key={ `${category.strCategory}` }
     value={ `${category.strCategory}` }
     data-testid={ `${category.strCategory}-category-filter` }
     onClick={ (e) => toggleFunc(endpoint, category.strCategory, e.target.value) }
    >
      {category.strCategory}
    </button>

and in office, I created a:

async function toggleFunc([serviceEndpoint, category], categoryValue) {
      await onClickCategoryFetch(serviceEndpoint, category);
      if (categoryValue !== 'all') {
        setSelectedCategory(categoryValue);
        if (selectedCategory === categoryValue) setToggle(false);
        else setToggle(true);
      } else setToggle(false);
    }

Browser other questions tagged

You are not signed in. Login or sign up in order to post.