Получите атрибут getAttribute от кнопки и переключите имя класса на крючки реакции тела

#javascript #reactjs #react-hooks

Вопрос:

я хочу улучшить свой код с помощью нескольких кнопок с пользовательскими именами классов (attr), при нажатии на которые следует добавить тег тела (переключатель), теперь добавляется первая кнопка только потому, что для ("button")[0] , но должна работать для каждой кнопки

 import React, { useState, useEffect } from "react"

function Test() {
  const [isClass, setIsClass] = useState(false)

  useEffect(() => {
    const x = document.getElementsByTagName("button")[0].getAttribute("custom-class")
    document.body.classList.toggle(x, isClass)
  }, [isClass])

  return (
    <>
      <button custom-class='test1' onClick={() => setIsClass(!isClass)}>
        Setting test1 className
      </button>
       
      <button custom-class='test2' onClick={() => setIsClass(!isClass)}>
        Setting test2 className
      </button>
    </>
  )
}

export default Test
 

Спасибо

Комментарии:

1. почему вы хотите добавить имя класса в основной тег? какой цели вы пытаетесь достичь?

2. Привет, @Наим Мустафа, Спасибо за ответ. для css в основном

Ответ №1:

Пожалуйста, используйте этот код.

 let oldStyle = "";

const handleClick = (index) => {
  const x = [...document.getElementsByTagName("button")].map(value => value.getAttribute("custom-class"));
  document.body.classList.contains(x[index]) ? document.body.classList.remove(x[index]) : document.body.classList.add(x[index]);
  if(document.body.classList.length > 1) document.body.classList.replace(oldStyle, x[index]);
  oldStyle = x[index];
}

return (
  <>
    <button custom-class='test1' onClick={() => handleClick(0)}>
      Setting test1 className
    </button>
    
    <button custom-class='test2' onClick={() => handleClick(1)}>
      Setting test2 className
    </button>
  </>
)
 

Комментарии:

1. Спасибо за ответ, добавляет два класса, <body class="test1 test2"></body> должен быть добавлен только один

2. Привет @Кирилл Савик, почти близко, первый щелчок, появляется класс, при повторном нажатии он должен исчезнуть, теперь он остается, он исчезает только при нажатии другой кнопки, при нажатии той же кнопки он должен переключаться

3. Спасибо @Кирилл Савик 1

Ответ №2:

Лучше не использовать запросы DOM и манипуляции непосредственно с элементами, которые создаются и управляются react. В вашем конкретном примере это нормально использовать document.body , но не нормально искать кнопки, особенно когда вы пытаетесь найти их по имени тега. Чтобы фактически переключить класс в списке классов, в большинстве случаев вам не нужен второй параметр, поэтому дополнительное состояние также не требуется.

Чтобы получить ссылку на отображение элемента с помощью React, используйте Ref. Однако в вашем конкретном случае побочный эффект может быть запущен внутри обработчика событий, поэтому вам не нужно useEffect или useRef .

Ваш onClick обработчик может принимать event объект, который является синтетическим событием. Он содержит цель свойства, которая содержит ссылку на вашу кнопку.

Итак, проще всего было бы просто написать так:

 function Test() {
  function clickHandler(event) {
    let classToToggle = event.target.getAttribute("custom-class");
    document.body.classList.toggle(classToToggle);
  }

  return (
    <>
      <button key="test1" custom-class="test1" onClick={clickHandler}>
        Setting test1 className
      </button>

      <button key="test2" custom-class="test2" onClick={clickHandler}>
        Setting test2 className
      </button>
    </>
  );
}

export default Test;
 

Если вам нужно иметь только одно имя класса из списка, вы можете решить, какой класс включить или отключить, немного указав состояние. Поскольку что угодно может добавлять классы в тело, может быть полезно работать только с некоторым набором классов, а не удалять все.

Кроме того, не упоминалось ранее, но рассмотрите возможность использования data атрибута, поскольку его цель-сохранить некоторые дополнительные данные.

 function Test() {
  // this can come from props or be hardcoded depending on your requirements
  // If you intend to change it in runtime, consider adding side effect to cleanup previous classes on body
  let [classesList] = React.useState(["test1", "test2"]);
  let [activeClass, setActiveClass] = React.useState("");

  // You can switch actual classes in effect, if you want to
  function clickHandler(event) {
    let classToToggle = event.target.dataset.customClass;
    // we remove all classes from body that are in our list
    document.body.classList.remove(...classesList);
    if (activeClass === classToToggle) {
      setActiveClass("");
    } else {
      // if class not active - set new one
      document.body.classList.add(classToToggle);
      setActiveClass(classToToggle);
    }
  }

  return (
    <>
      {classesList.map((cn) => (
        <button key="cn" data-custom-class={cn} onClick={clickHandler}>
          Setting {cn} className
        </button>
      ))}
    </>
  );
}
 

Комментарии:

1. Спасибо @Mr. Еж, работает нормально, но при нажатии обеих кнопок добавляется два класса, можно удалить предыдущее имя класса

2. О, я думал, что это то, чего ты хочешь. Для переключения различных имен классов у вас есть множество вариантов, и жизнеспособный вариант зависит от вашего конкретного приложения. Дело в том, что все на странице может добавлять классы в тело, поэтому, если вам нужно только манипулировать определенным набором и не вмешиваться в то, что у вас было ранее, рассмотрите эту логику. Если текущий класс уже активен, включите, если выключен. Если текущий класс не активен — удалите все классы из тела, которые есть в вашем списке, и добавьте новый активный класс. Это можно сделать как с эффектом, так и без него — выберите то, что лучше соответствует вашему окончательному коду. Я скоро отредактирую свой ответ.