簡體   English   中英

mouseEnter 和 mouseLeave 適用於 HTML 個元素,但不適用於 React 組件?

[英]mouseEnter and mouseLeave work on HTML elements, but not React components?

第一次制作 React 站點(使用 Gatsby)。

想要發生什么

在我的索引頁面上,我試圖在鼠標懸停在Term組件上時顯示一個Note組件。

發生了什么

當我將onMouseEnteronMouseLeave直接添加到Term組件時, Note永遠不會出現。 但是,如果我使用本機 html 元素(下面示例代碼中的span )而不是<Term/> ,則Note會出現。

跟箭頭function有關系嗎?

  • () => setShowNoteB(true)替換為console.log("in TermB") (某種程度上)有效。
  • 但是使用onMouseEnter={setShowNoteB(true)}會導致無限循環錯誤。

它與我如何組成組件有關嗎? 還是useState掛鈎的限制? 我在這里做的事情看起來相當簡單/直接,但同樣,我是新手,所以也許有一些我不知道的規則。

示例代碼

索引頁

//index.js

import * as React from 'react';
import { useState } from 'react';
import Term from '../components/term';
import Note from '../components/note';


const IndexPage = () => {
  const [showNoteA, setShowNoteA] = useState(false);
  const [showNoteB, setShowNoteB] = useState(false);

  return (
    <>
      <h1
      >
        <span
          onMouseEnter={() => setShowNoteA(true)}
          onMouseLeave={() => setShowNoteA(false)}
        > TermA* </span>
        {" "} doesn't behave like {" "}
        <Term word="TermB" symbol="†"
          onMouseEnter={() => setShowNoteB(true)}
          onMouseLeave={() => setShowNoteB(false)}
        />
      </h1>

      {showNoteA ? <Note> <p>This is a note for TermA.</p> </Note> : null}
      {showNoteB ? <Note> <p>This is a note for TermB.</p> </Note> : null}
    </>
  );
};

export default IndexPage

術語組件

// term.js

import React from 'react';

const Term = ({ word, symbol }) => {

  return (
    <div>
      <span>{word}</span>
      <span>{symbol}</span>
    </div>
  );
};

export default Term;

注釋組件

// note.js

import * as React from 'react';

const Note = ({ children })=> {
  return (
    <div>
      {children}
    </div>
  )
};

export default Note;

使用useEffectuseRefforwardRefaddEventListener/removeEventListener的解決方案:

應用程序.js

import React, { useRef } from 'react';

import Term from './Term';

export default function App() {
  const ref = useRef({});

  return (
    <div>
      Lorem ipsum dolor sit amet,{' '}
      <Term ref={ref} word="consectetur" symbol="†" /> adipiscing elit. Morbi
      laoreet <Term ref={ref} word="lacus" /> in dui vestibulum, nec imperdiet
      augue vulputate.
    </div>
  );
}

如果你想添加其他術語,只需創建一個新的 Term 組件並添加refwordsymbol (可選)道具。

術語.js

import React, { useState, useEffect, forwardRef } from 'react';

import Note from './Note';

function Term({ word, symbol }, ref) {
  const [isHovered, setHovered] = useState(false);
  const [currentTerm, setCurrentTerm] = useState('');
  const [currentSymbol, setCurrentSymbol] = useState('');

  useEffect(() => {
    if (ref.current && word) {
      ref.current[word].addEventListener('mouseover', handleMouseover);
      ref.current[word].addEventListener('mouseout', handleMouseout);

      return () => {
        ref.current[word].removeEventListener('mouseover', handleMouseover);
        ref.current[word].removeEventListener('mouseout', handleMouseout);
      };
    }
  }, [ref.current, word]);

  const handleMouseover = () => {
    setHovered(true);
    setCurrentTerm(word);
    setCurrentSymbol(symbol);
  };

  const handleMouseout = () => {
    setHovered(false);
    setCurrentTerm('');
    setCurrentSymbol('');
  };

  return (
    <>
      <span ref={(elem) => (ref.current[word] = elem)}>
        {word}
      </span>
      {isHovered ? <Note word={currentTerm} symbol={currentSymbol} /> : null}
    </>
  );
}

const forwarded = forwardRef(Term);
export default forwarded;

筆記.js

import React from 'react';

export default function Note({ word, symbol }) {

  const checkTerm = (term) => {
    switch (term) {
      case 'consectetur':
        return `definition`;
      case 'lacus':
        return `definition`;
      default:
        return null;
    }
  };

  return (
    <div>
      <p>
        {word} {symbol ? symbol : '-'}
      </p>
      <p>{checkTerm(word)}</p>
    </div>
  );
}

演示: Stackblitz

當您在 JSX 中使用組件時,與(小寫的)HTML 標簽相反,任何屬性僅作為 prop 傳遞,不會直接產生進一步的影響。

<Term
  word="TermB" symbol="†"
  onMouseEnter={() => setShowNoteB(true)}
  onMouseLeave={() => setShowNoteB(false)}
/>

您需要獲取傳遞的 prop 並將其分配給組件 JSX 中的實際 HTML 元素,如下所示:

const Term = ({ word, symbol, onMouseEnter, onMouseLeave }) => {
  return (
    <div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
      <span>{word}</span> <span>{symbol}</span>
    </div>
  );
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM