[英]What is the best practice to close a DropDown on a Link click in React?
我有以下代码: Link to Sandbox
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Switch, Link } from "react-router-dom";
import "./styles.css";
function DropDown({ close }) {
return (
<ul>
<li>
<Link to="/" onClick={close}>
Page 1
</Link>
</li>
<li>
<Link to="/page2" onClick={close}>
Page 2
</Link>
</li>
<li>
<p>Dont hide dropdown when clicking me!</p>
</li>
</ul>
);
}
function Header() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(prev => !prev)}>Toggle DropDown</button>
{isOpen && <DropDown close={() => setIsOpen(false)} />}
</div>
);
}
function Page1() {
return <h1>Page 1</h1>;
}
function Page2() {
return <h1>Page 2</h1>;
}
function App() {
return (
<div className="App">
<BrowserRouter>
<Header />
<Switch>
<Route exact path="/" component={Page1} />
<Route path="/page2" component={Page2} />
</Switch>
</BrowserRouter>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
如果不总是将close
回调向下传递到下拉列表中的每个链接,我该如何实现呢?
我试图用一个钩子来实现这个,这个钩子监听mousedown
并检查它是否在下拉列表中并点击类型 A 但问题是它在反应重定向到路由之前关闭下拉列表。
我已经用 useClickAway 钩子覆盖了外面的点击,但我还需要一个 useClickInsideOnLink 钩子。
您可以在DropDown
组件中创建一个内部组件,并默认使用close
function ,还可以通过rest parameter
传递其他道具。 像这样的东西:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Switch, Link } from "react-router-dom";
import "./styles.css";
function DropDown({ close }) {
const MyLink = ({...rest}) => {
return (
<Link {...rest} onClick={close}>
Page 1
</Link>
)
}
return (
<ul>
<li>
<MyLink to="/">
Page 1
</MyLink>
</li>
<li>
<MyLink to="/page2">
Page 2
</MyLink>
</li>
<li>
<p>Dont hide dropdown when clicking me!</p>
</li>
</ul>
);
}
function Header() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(prev => !prev)}>Toggle DropDown</button>
{isOpen && <DropDown close={() => setIsOpen(false)} />}
</div>
);
}
function Page1() {
return <h1>Page 1</h1>;
}
function Page2() {
return <h1>Page 2</h1>;
}
function App() {
return (
<div className="App">
<BrowserRouter>
<Header />
<Switch>
<Route exact path="/" component={Page1} />
<Route path="/page2" component={Page2} />
</Switch>
</BrowserRouter>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
我认为您(至少)有两个选择:
另一种可能的方式(我不推荐它,因为它给一个简单的问题增加了不必要的复杂性)(由提问者的评论添加):
实际上,当 props 更改或 state 更改时,组件会更新。 引用 react 文档:如果您想在 prop 更改时“重置”某些 state ,请考虑使用密钥完全控制或完全不受控制的组件。 完全不受控制的将是选项 2。
要触发道具的变化,您可以将Header与Router 连接。 这样,当位置(和其他路由道具)发生变化时,Header 组件就会得到通知。 基于此,您可以通过生命周期方法组件DidUpdate 对 isOpen state 应用更新,并将先前的 location.pathname 与当前的比较,如果路径名更改,则将 isOpen 设置回 false。 其实我不建议这样做。 但是在这里你 go: CodeSandbox
可能为时已晚,但如果它不能帮助某人:您可以从 useLocation() 挂钩中解构路径名,并且在每次路径名更改时,您可以在 useEffect 中将 isOpen 设置为 false。
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Switch, Link, useLocation } from "react-router-dom";
import "./styles.css";
function DropDown({ close }) {
const MyLink = ({...rest}) => {
return (
<Link {...rest}>
Page 1
</Link>
)
}
return (
<ul>
<li>
<MyLink to="/">
Page 1
</MyLink>
</li>
<li>
<MyLink to="/page2">
Page 2
</MyLink>
</li>
<li>
<p>Dont hide dropdown when clicking me!</p>
</li>
</ul>
);
}
function Header() {
const [isOpen, setIsOpen] = useState(false);
const { pathname } = useLocation();
useEffect(() =>{
setIsOpen(false);
}, [pathname])
return (
<div>
<button onClick={() => setIsOpen(prev => !prev)}>Toggle DropDown</button>
{isOpen && <DropDown close={() => setIsOpen(false)} />}
</div>
);
}
function Page1() {
return <h1>Page 1</h1>;
}
function Page2() {
return <h1>Page 2</h1>;
}
function App() {
return (
<div className="App">
<BrowserRouter>
<Header />
<Switch>
<Route exact path="/" component={Page1} />
<Route path="/page2" component={Page2} />
</Switch>
</BrowserRouter>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
尝试像这样订阅当前位置:
const location = useLocation();
useEffect(() => {
closeHeader();
}, [location]);
我猜这个不错;3
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.