Обновление стиля одного элемента при наведении курсора мыши на другой элемент Реагирует

#javascript #reactjs

#javascript #reactjs

Вопрос:

У меня есть элемент tab, куда переходит вкладка — это активная вкладка, определяемая реквизитами, там есть подчеркивание.

Он оформлен значением состояния underlineStyle .

При начальной загрузке состояние для sizes не обновилось к моменту его достижения, getUnderlineStyle которое вызывается впоследствии?

Причина, по которой я не делаю этого с помощью CSS, заключается в том, что есть переход, который требует некоторых вычислений в getSizes() , поэтому он имеет правильные значения свойств left и right из объекта, на который sizes вы можете видеть ссылки.

Как я могу вызвать, getUnderlineStyle() чтобы применить правильный стиль после того, как sizes состояние было обновлено?

Ниже приведен фрагмент из моего компонента.

 const Tabs = (props) => {
   const [sizes, updateSizes] = useState({});
   const [underlineStyle, updateUnderlinStyle] = useState({});

   useEffect(() => {
      if (props.underline) {
         getSizes();
         // State for sizes does not seem to get updated here?
         getUnderlineStyle();
         window.addEventListener("resize", _.debounce(() => getSizes()));
      }
   },
      [props]
   );

   let els = {};

   const tabsRef = useRef(null);

   const transistionTime = 500;
   const transistionStyle = `left ${transistionTime}ms, right ${transistionTime}ms`;

   const getSizes = () => {
      const rootBounds = tabsRef.current.getBoundingClientRect();

      const size = {};

      Object.keys(els).forEach((key) => {
         const el = els[key];
         const bounds = el.getBoundingClientRect();
         const left = bounds.left - rootBounds.left;
         const right = rootBounds.right - bounds.right;

         size[key] = { left, right };
      });

      // This updates size state, but does not seem to carry across into getUnderlineStyle???
      updateSizes(size);

   }

   const getUnderlineStyle = (active) => {
      // the state, `size` is still set to it's default value of an empty object, hit first condition, should hit last on initial load?
      if (props.active == null || Object.keys(sizes).length === 0) {
         updateUnderlinStyle({ left: '0', right: '100%' });
      } else if (active) {
         updateUnderlinStyle({
            left: sizes[active].left,
            right: sizes[active].right,
            transition: transistionStyle
         })
      } else {
         updateUnderlinStyle({
            left: sizes[props.active].left,
            right: sizes[props.active].right,
            transition: transistionStyle
         });
      }
   }

   return (
      <div className="Tabs" ref={tabsRef}>
         {React.Children.map(props.children, (child, i) => {
            return (
               <div
                  className={(child.key === props.active ? 'Tabs-item Tabs-itemActive' : 'Tabs-item')   (i === 0 ? ' Tabs-first' : i === (props.children.length - 1) ? ' Tabs-last' : null)}
                  onClick={() => {
                     // Call onChange method in Parent Component
                     props.onChange(child.key);
                  }}
                  onMouseOver={() => getUnderlineStyle(child.key)}
                  ref={el => els[child.key] = el}
               >
                  {child}
               </div>
            )
         })}
         {props.underline ?
            <div key={"Tabs-underline"} className="Tabs-underline" style={underlineStyle}></div>
            : null
         }
      </div>
   );
};

export default Tabs;
  

Ответ №1:

Сначала вам нужно либо преобразовать ваш компонент в Class , либо использовать перехватчики для реализации состояния в вашем компоненте. Поскольку Class по-прежнему более распространены, чем хуки, я соглашусь с этим для этого ответа

Вы можете добавить прослушиватель событий в компонент, над которым вы хотите запустить действие при наведении курсора мыши, и в этой функции изменить состояние вашего компонента. Тогда у вас может быть условный стиль / класс, который применяется только тогда, когда это состояние истинно. Также вам нужно убедиться, что ваша setState функция вызывается только один раз, чтобы предотвратить множество ненужных вызовов. Простой пример:

 Class Tabs extends React.Component{
constructor(props){
  super(props);

  this.state = {
    isHovered: false
  }

 // Needed to keep the reference to this
 this.onHover = this.onHover.bind(this);
 this.onHoverEnd = this.onHoverEnd.bind(this);
}

render(){
   const { isHovered } = this.state;

    // Classes
    // Ternary operator: acts like a If/else
    const hoverClass = isHovered? "yourClass" : "";

    return(
    <div id="root">
      <div onMouseEnter={this.onHover} onMouseLeave={this.onHoverEnd} />
      <div className={hoverClass} />
    </div>
  )
}

onHover(){
  const { isHovered } = this.state;

  if(!isHovered){
    this.setState({isHovered: true})
    }
  }

onHoverEnd(){
 const { isHovered } = this.state;

  if(isHovered){
    this.setState({isHovered: false})
    }
  }
 } 
}
  

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

1. Возможно, мне придется пойти по пути компонента на основе классов, просто мы хотели использовать в нашем веб-приложении, где это возможно, функцию на основе.

2. @mcclosa тогда вы могли бы использовать хуки, которые в основном делают то же самое, но сохраняют функциональность компонента. Вот документация: reactjs.org/docs/hooks-intro.html

3. @Fredric Caplette Разве это не то, что я использую выше?

4. @mcclosa Ах, умница! Да, вы правы. Я еще не пробовал сам использовать хуки, поэтому пока ничем не могу помочь, если вы непременно хотите использовать хуки.

5. Если я все еще застряну к концу дня, я попробую метод на основе класса и приму ваш ответ.

Ответ №2:

итак, ваш вопрос вкратце

«Возможно ли динамически обновлять стиль подчеркивания вкладок, когда пользователь наводит курсор на элемент Tabs?»

ответ: «да» 🙂

в react вы можете определять «состояния» и «монтировать» / «привязывать» их для ваших конкретных нужд! я не могу сейчас написать код для мобильных устройств, но взгляните сюда: https://reactjs.org/docs/state-and-lifecycle.html

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

1. Спасибо, вскоре после публикации я понял, что нужно использовать state. Извините, я был брошен в глубокий конец с React, поэтому медленно подбираю его. У меня все еще возникают проблемы, когда я должен вызывать функцию для обновления состояния, она зависит от другого значения состояния и, похоже, не обновилась к моменту, когда я вызвал функцию? Извините, если это действительно элементарно, но в данный момент я не могу разобраться в этом.

2. не волнуйся, чувак, нам всем нужно было с чего-то начинать: D ты пробовал обработчик событий в Mouseenter? (ссылка: reactjs.org/docs/handling-events.html )

3. Обработчик события onMouseOver — это то, где он работает, это при начальной загрузке, где стиль применяется некорректно из-за того, что состояние sizes не обновляется при getUnderlineStyles вызове в useEffect . Извините, если я неправильно понял, что вы имели в виду?