React ловит эффект зависания - PullRequest
1 голос
/ 02 мая 2020

Я пытаюсь создать эффект наведения при помощи реагирующих хуков. Я написал функцию для наведения на основе некоторых руководств

function useHover() {
  const [hovered, setHovered] = useState(false);

  const ref = useRef(null);

  const handleMouseOver = () => setHovered(true);
  const handleMouseOut = () => setHovered(false);

  useEffect(() => {
    const node = ref.current;
    if (node) {
      node.addEventListener("mouseover", handleMouseOver);
      node.addEventListener("mouseout", handleMouseOut);

      return () => {
        node.removeEventListener("mouseover", handleMouseOver);
        node.removeEventListener("mouseout", handleMouseOut);
      };
    }
  }, [ref]);

  return [ref, hovered];
}

, но как заставить ее работать в моей функции приложения

export default function App() {
  const [ref, isHovered] = useHover();

  const reactionItems = myObject.map(([key, value]) => (
    <li key={key} ref={ref}>
      {isHovered ? `${key} ${value.length > 1 ? "x " + value.length : ""}` : `${key} ${value.length > 1 ? "x " + value.length : ""} ${value}`}
    </li>
  ));


return (
    <div className="App">
      <h1>{string}</h1>
      <h2>Reactions</h2>
      <ul>{reactionItems}</ul>
    </div>
  );

} 

Я могу видеть это только в состоянии false, поэтому второй вариант и без эффекта наведения

Ответы [ 2 ]

1 голос
/ 02 мая 2020

Используйте Реагирует на систему событий , а не на DOM. Кроме того, у каждого элемента должны быть свои собственные обработчики событий и состояние.

Создайте ловушку, которая возвращает состояние зависания, и прослушиватели событий элемента. Создайте компонент Item и используйте хук в его определении. Рендеринг предметов.

const { useState, useMemo } = React;

const useHover = () => {
  const [hovered, setHovered] = useState();
  
  const eventHandlers = useMemo(() => ({
    onMouseOver() { setHovered(true); },
    onMouseOut() { setHovered(false); }
  }), []);
  
  return [hovered, eventHandlers];
}

const Item = ({ children }) => {
  const [hovered, eventHandlers] = useHover();

  return (
    <li {...eventHandlers}>Item: {hovered && children}</li>
  );
};

const myObject = {
  a: 'A1',
  b: 'B2',
  c: 'C3',
}

function App() {
  const reactionItems = Object.entries(myObject)
    .map(([key, value]) => (
      <Item key={key}>{value}</Item>
    ));

  return (
    <div className="App">
      <h2>Reactions</h2>
      <ul>{reactionItems}</ul>
    </div>
  );
}

ReactDOM.render(<App />, root);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>
0 голосов
/ 02 мая 2020

Один из способов сделать это - использовать события React, и просто убедиться, что он более универсален. c.

Одна из проблем, с которыми вы столкнулись, заключается в том, что ссылка может ссылаться только на один узел за раз. И ref никогда не изменяет зависимости, поэтому useEffect запускается только один раз.

const { useState, useRef, useEffect, useCallback } = React;

function useHover() {
  const [hovered, setHovered] = useState({});

  const mouseOver = useCallback((event) => {
    const target = event.target;
    const key = target.getAttribute('data-key');
    setHovered((curState) => ({ ...curState, [key]: true }));
  }, []);

  const mouseOut = useCallback((event) => {
    const target = event.target;
    const key = target.getAttribute('data-key');
    setHovered((curState) => ({ ...curState, [key]: false }));
  }, []);

  return { mouseOver, mouseOut, hovered };
}

const object = { key1: 'test', key2: 'test2', key3: 'test3' };
const myObject = Object.entries(object);
const string = 'Header';
function App() {
  const { mouseOver, mouseOut, hovered } = useHover();

  const reactionItems = myObject.map(([key, value]) => (
    <li key={key} data-key={key} onMouseOver={mouseOver} onMouseOut={mouseOut}>
      {hovered[key]
        ? `${key} ${value.length > 1 ? 'x ' + value.length : ''}`
        : `${key} ${value.length > 1 ? 'x ' + value.length : ''} ${value}`}
    </li>
  ));

  return (
    <div className="App">
      <h1>{string}</h1>
      <h2>Reactions</h2>
      <ul>{reactionItems}</ul>
    </div>
  );
}

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

Вы также можете разделить элементы списка на их собственный компонент, который позволит вам работать с useHover более близко к тому, как у вас это было.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...