mouseEnter 和 mouseLeave 在 HTML 元素上工作,而不是 React 组件?
mouseEnter and mouseLeave work on HTML elements, but not React components?
第一次制作 React 网站(使用 Gatsby)。
我想要发生的事情
在我的索引页面上,我试图在鼠标悬停在 Term
组件上时显示 Note
组件。
正在发生什么
当我将 onMouseEnter
和 onMouseLeave
直接添加到 Term
组件时,Note
永远不会出现。但是,如果我使用本机 html 元素(下面示例代码中的 span
)而不是 <Term/>
,则会出现 Note
。
和箭头函数有关系吗?
- 用
console.log("in TermB")
替换 () => setShowNoteB(true)
(有点)有效。
- 但是使用
onMouseEnter={setShowNoteB(true)}
会导致无限循环错误。
这与我如何编写组件有关吗?还是 useState
挂钩的限制?
我在这里做的事情看起来相当 simple/straightforward,但是我还是新手,所以可能有一些我不知道的规则。
示例代码
索引页
//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;
useEffect
、useRef
、forwardRef
和 addEventListener/removeEventListener
的解决方案:
App.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 组件并添加 ref
、word
、symbol
(可选)道具。
Term.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;
Note.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)}
/>
您需要获取传递的属性并将其分配给组件 JSX 中的实际 HTML 元素,如下所示:
const Term = ({ word, symbol, onMouseEnter, onMouseLeave }) => {
return (
<div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
<span>{word}</span> <span>{symbol}</span>
</div>
);
};
第一次制作 React 网站(使用 Gatsby)。
我想要发生的事情
在我的索引页面上,我试图在鼠标悬停在 Term
组件上时显示 Note
组件。
正在发生什么
当我将 onMouseEnter
和 onMouseLeave
直接添加到 Term
组件时,Note
永远不会出现。但是,如果我使用本机 html 元素(下面示例代码中的 span
)而不是 <Term/>
,则会出现 Note
。
和箭头函数有关系吗?
- 用
console.log("in TermB")
替换() => setShowNoteB(true)
(有点)有效。 - 但是使用
onMouseEnter={setShowNoteB(true)}
会导致无限循环错误。
这与我如何编写组件有关吗?还是 useState
挂钩的限制?
我在这里做的事情看起来相当 simple/straightforward,但是我还是新手,所以可能有一些我不知道的规则。
示例代码
索引页
//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;
useEffect
、useRef
、forwardRef
和 addEventListener/removeEventListener
的解决方案:
App.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 组件并添加 ref
、word
、symbol
(可选)道具。
Term.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;
Note.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)}
/>
您需要获取传递的属性并将其分配给组件 JSX 中的实际 HTML 元素,如下所示:
const Term = ({ word, symbol, onMouseEnter, onMouseLeave }) => {
return (
<div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
<span>{word}</span> <span>{symbol}</span>
</div>
);
};