Toggle boolean state (React). Переключение state типа boolean и переключение класса элемента на основе state

Довольно часто возникает задача добавть/удалить класс элементу в React по какому-либо переключателю, пусть даже, по одной кнопке на основе state. В примере применяем класс на компонент, по которому происходит клик.

Есть у нас компонент MyComponent с состоянием, в котором хранится отметка (state) о выполнении чего-либо (done) в этом компоненте. Наш state done может быть true или false. Так же имеется обработчик клика (handleClick), который меняет состояние.
Заметьте, установка состояния при его определении и переустановка производится без this.
А обращение к текущему состоянию из метода setState производится с помощью полной вложенности до конкретного state компонента (this.state.done).
Для упрошения обращению к state внутри render, деструктуризируем state

const { done } = this.state

Класс, который нам нужно применить или убрать у элемента, находится в импортируемом файле MyComponent.module.scss с алиасом 's' (сокращение от style) и называется done (обращаемя к нему s.done).
Для упрощения манипуляции с классами, поместим их в массив elementClass и добавим простое условие проверки state, на основе которого добавляем или удаляем из массива класс, за который мы сделали ответственным наш state.

Уже в самом элементе мы применяем join к массиву классов и навешиваем обработчик события

import React from 'react';
import s from './MyComponent.module.scss';
class MyComponent extends React.Component {

    state = {
        done: false,
    }

    handleClick = () => {
        this.setState(
            {
                done: !this.state.done,
            }
        )
    }

    render() {
        const { done } = this.state
        const elementClass = [s.someClass, s.anotherClass]

        if (done) {
            elementClass.push(s.done)
        } else {
            if(elementClass.indexOf(s.done) !== -1) {
                elementClass.splice(elementClass.indexOf(s.done), 1);
            }
        }
        return (
            <div
                className={elementClass.join(' ')}
                onClick={this.handlerClick}
            >
            //...
            </div>
       );
    }
}

export default MyComponent;

Key Words for FKN + antitotal forum (CS VSU):

vedro-compota's picture

С Использование логических выражений в JSX, проверяя пропсы или стейт (как в примере ниже, напр. с помощью тернарого оператора) в React можно вообще не выводить элемент (если стоит цель его именно скрыть - убрать а не поменять стиль, т.е. CSS не нужен):

      {(!state.isInProcess && state.completedSuccess) ?
        <Redirect to={RoutePath('index')} />
        :
        <span><b>Ошибка:</b> <i>{state.errorMessage}</i>
          <br />
          Не удалось подтвердить адрес электронной почты.
        </span>
      }

-- в данном случае в зависимости от значения логического выражения, начинает исполняться тот или иной JSX-код, а значит и на экране появятся разные html фрагменты (в зависимости от значения лог. выражения).

_____________
матфак вгу и остальная классика =)

Да, для вывода/скрытия элемента (вывода одного из двух) так и нужно поступить, но если необходимо поменять стиль элемента, у которого есть содержимое и какая-то логика, то проще добавить/удалить класс элемента

vedro-compota's picture

да, стили конечно через класс меняются. Класс можно тоже выводить или не выводить тренарным оператором. Но если у вас там много классов, то тогда пример выше конечно подходит, просто он не очень простой)

_____________
матфак вгу и остальная классика =)

В методе render() в условии проверки done,

        if (done) {
            cardClass.push(s.done)
        } else {
            if(cardClass.indexOf(s.done) !== -1) {
                cardClass.splice(cardClass.indexOf(s.done), 1);
            }
        }

блок else лишний, т.к.

elementClass = [s.someClass, s.anotherClass]
 

Будет каждый раз создаваться заново и в ней не будет s.done