在React中构建自定义下拉菜单,并在单击外部时尝试关闭它时遇到问题。
因此,我创建了通用HOC,因此也可以将其用于其他场合。
我似乎遇到的问题是我不知道如何将ref
从临时项目传递到组件。
我一直在研究forwardRef和示例的其他基调,但我想不通。
知道是否有可能以及我该怎么做?
import React, { useState, useRef, useEffect } from "react";
export default function withClickOutside(WrappedComponent) {
const Component = (props) => {
const [open, setOpen] = useState(false);
const ref = useRef();
useEffect(() => {
const handleClickOutside = (event) => {
if (!ref?.current?.contains(event.target)) {
setOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
}, [ref]);
return <WrappedComponent {...props} open={open} setOpen={setOpen} ref={ref}/>;
};
return Component;
}
答案 0 :(得分:3)
您需要处理ref
传递的内容,以便它实际附加到某物上:
const Home = forwardRef(({ open, setOpen }, ref) => {
console.log(open);
return (
<section ref={ref}>
<h1>Feels good to be home!</h1>
<button className="secondary" onClick={() => setOpen(!open)}>
Dropdown Toggle
</button>
{open && (
<ul>
<li>One</li>
<li>Two</li>
</ul>
)}
</section>
);
});
答案 1 :(得分:0)
您可以查看网站:
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select';
const useStyles = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}));
export default function SimpleSelect() {
const classes = useStyles();
const [age, setAge] = React.useState('');
const handleChange = (event) => {
setAge(event.target.value);
};
return (
<div>
<FormControl variant="filled" className={classes.formControl}>
<InputLabel id="demo-simple-select-filled-label">Age</InputLabel>
<Select
labelId="demo-simple-select-filled-label"
id="demo-simple-select-filled"
value={age}
onChange={handleChange}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</div>
);
}
此外,您可以在CodeSandbox上看到更详细的示例
答案 2 :(得分:0)
有点区别。从您的方法,但此挂钩可用于包装您的按钮和菜单。
/**
* This Hook can be used for detecting clicks outside the Opened Menu
*/
function clickOutside(ref, onClickOutside) {
useEffect(() => {
/**
* Invoke Function onClick outside of element
*/
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
onClickOutside();
}
}
// Bind
document.addEventListener("mousedown", handleClickOutside);
return () => {
// dispose
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref, onClickOutside]);
}
包含您的代码:
const Home = () => {
let [open, setOpen] = useState(false);
const wrapperRef = useRef("menu");
outsideClickAlert(wrapperRef, () => {
setOpen(false);
});
return (
<section>
<h1>Feels good to be home!</h1>
<div ref={wrapperRef}>
<button className="secondary" onClick={() => setOpen(!open)}>
Dropdown Toggle
</button>
{open && (
<ul>
<li>One</li>
<li>Two</li>
</ul>
)}
</div>
</section>
);
};