I am making a search input where people can look for skills and then choose a skill from the choices. However, when I click on any of the options, it calls the event listener for the parent element ( onBlur={() => setIsFocus(false)}
). When I remove this event listener, it adds a new skill, but when it is there, it does not run the function that is attached to the child element.
I tried to add e.stopPropagtion()
to the child element, but it didn't work.
My Code:
import { useRef, useState } from "react"
import fetchSkills from "../api"
import BaseInput from "../components/reusable/BaseInput"
import SkillsSuggestionList from "../components/solutions/SkillsSuggestionList"
import Icons from "../components/SvgIcons/Icons"
import { debounce } from "../utils/shared"
const SKILLS = [
{ name: "html" },
{ name: "css" },
{ name: "javascript" },
{ name: "bootstrap" },
{ name: "tailwind-css" },
{ name: "react" },
{ name: "vue" },
{ name: "angular" },
]
const SolutionForm = () => {
const [skills, setSkills] = useState([])
const [isFocus, setIsFocus] = useState(false)
const selectRef = useRef(null)
// fetch skills and render them in a SkillsSuggestionList component
const handleSelectChange = async (e) => {
const { value } = e.target
if (value.length > 2) {
const result = await fetchSkills(value)
setSkills(result.items)
}
}
const addSkill = (skill) => {
setData({
...data,
skills: [...data.skills, skill],
})
setIsFocus(false)
setSkills([])
selectRef.current.value = ""
}
return (
<div>
<div>
<form onSubmit={handleSubmit}>
<div
key={input.name}
onBlur={() => setIsFocus(false)} // this is a parent event listener
>
<div
key={input.name}
>
<ul>
{data.skills.map((skill, index) => (
<li key={index}>
{skill}
</li>
))}
</ul>
<BaseInput
onChange={debounce(handleSelectChange, 500)}
onFocus={() => setIsFocus(true)}
name={input.name}
innerRef={selectRef}
/>
</div>
{isFocus && (
<SkillsSuggestionList
skills={skills.length > 0 ? skills : SKILLS}
addSkill={addSkill}
/>
)}
</div>
</form>
</div>
</div>
)
}
export default SolutionForm
SkillSuggestionList component:
const SkillsSuggestionList = ({ skills, addSkill }) => {
return (
<ul
id="skills"
>
{skills.map((skill) => (
<li
onClick={(e) => { // this is a child event listener
e.stopPropagation()
addSkill(skill.name)
}}
key={skill.name}
>
{skill.name}
</li>
))}
</ul>
)
}
export default SkillsSuggestionList
Using onMouseDown instead of onClick will do the trick.
{skills.map((skill) => (
<li
onMouseDown={(e) => { // this is a child event listener
// e.stopPropagation() <--- this won't be needed
addSkill(skill.name)
}}
key={skill.name}
>
{skill.name}
</li>
))}
Also, let me explain why onMouseDown is needed here. When you click the list, before onClick run it blurs down and the function is no longer available. So when you use onMouseDown it will first run the addSkill function and then blur it. Hop it will work.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.