Javascript 在React中关闭链接点击下拉列表的最佳做法是什么?

Javascript 在React中关闭链接点击下拉列表的最佳做法是什么?,javascript,reactjs,dropdown,dom-events,Javascript,Reactjs,Dropdown,Dom Events,我有以下代码: import React,{useState}来自“React”; 从“react dom”导入react dom; 从“react router dom”导入{BrowserRouter,Route,Switch,Link}; 导入“/styles.css”; 函数下拉列表({close}){ 返回( 第1页 第2页 单击我时不要隐藏下拉列表 ); } 函数头(){ 常量[isOpen,setIsOpen]=useState(false); 返回( setIsO

我有以下代码:

import React,{useState}来自“React”;
从“react dom”导入react dom;
从“react router dom”导入{BrowserRouter,Route,Switch,Link};
导入“/styles.css”;
函数下拉列表({close}){
返回(
  • 第1页
  • 第2页
  • 单击我时不要隐藏下拉列表

); } 函数头(){ 常量[isOpen,setIsOpen]=useState(false); 返回( setIsOpen(prev=>!prev)}>切换下拉列表 {isOpen&&setIsOpen(false)}/> ); } 函数Page1(){ 返回第1页; } 函数第2页(){ 返回第2页; } 函数App(){ 返回( ); } const rootElement=document.getElementById(“根”); render(,rootElement);
如何实现这一点而不总是向下拉列表中的每个链接传递
close
回调

我试图用一个钩子来实现这一点,钩子监听
mousedown
并检查它是否在下拉列表中,然后单击类型a,但问题是,它在react重定向到路由之前关闭下拉列表


我已经用useClickAway钩子覆盖了ClickOutside,但我也需要useClickInsideOnLink钩子

您可以在
下拉列表中创建一个内部组件,默认情况下使用
关闭
功能,还可以通过
rest参数传递其他道具。大概是这样的:

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);
import React,{useState}来自“React”;
从“react dom”导入react dom;
从“react router dom”导入{BrowserRouter,Route,Switch,Link};
导入“/styles.css”;
函数下拉列表({close}){
常量MyLink=({…rest})=>{
返回(
第1页
)
}
返回(
  • 第1页
  • 第2页
  • 单击我时不要隐藏下拉列表

); } 函数头(){ 常量[isOpen,setIsOpen]=useState(false); 返回( setIsOpen(prev=>!prev)}>切换下拉列表 {isOpen&&setIsOpen(false)}/> ); } 函数Page1(){ 返回第1页; } 函数第2页(){ 返回第2页; } 函数App(){ 返回( ); } const rootElement=document.getElementById(“根”); render(,rootElement);
您可以在
下拉列表中创建一个内部组件,默认情况下使用
关闭
功能,还可以通过
rest参数传递其他道具。大概是这样的:

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);
import React,{useState}来自“React”;
从“react dom”导入react dom;
从“react router dom”导入{BrowserRouter,Route,Switch,Link};
导入“/styles.css”;
函数下拉列表({close}){
常量MyLink=({…rest})=>{
返回(
第1页
)
}
返回(
  • 第1页
  • 第2页
  • 单击我时不要隐藏下拉列表

); } 函数头(){ 常量[isOpen,setIsOpen]=useState(false); 返回( setIsOpen(prev=>!prev)}>切换下拉列表 {isOpen&&setIsOpen(false)}/> ); } 函数Page1(){ 返回第1页; } 函数第2页(){ 返回第2页; } 函数App(){ 返回( ); } const rootElement=document.getElementById(“根”); render(,rootElement);
我认为您(至少)有两种选择:

  • 将页眉移动到页面中(由于呈现了新页面,页眉将重新初始化)。分叉你的代码沙盒
  • 让下拉菜单自己处理它的状态,并在下拉菜单中包含切换按钮。参见代码沙盒
另一种可能的方法(我不推荐它,因为它会给一个简单的问题增加不必要的复杂性)(由提问者的评论添加):


  • 实际上,当道具改变或状态改变时,组件会更新 变化。引用react docs:如果您想在 一个道具改变< /强>,考虑使一个组件<强> < /强> 或者用钥匙代替。完全不受控制将是不可能的 那么选择2


    要触发道具的更改,可以连接标题。 这样,当位置(和 其他路由道具)更改。基于此,可以对等参线应用更新 通过 并将以前的location.pathname与当前的location.pathname进行比较,如果路径名发生更改,则将isOpen设置回false。 事实上,我不建议这样做。但你看:

    • 我认为您(至少)有两种选择:

      • 将页眉移动到页面中(由于呈现了新页面,页眉将重新初始化)。分叉你的代码沙盒
      • 让下拉菜单自己处理它的状态,并在下拉菜单中包含切换按钮。参见代码沙盒
      另一种可能的方法(我不推荐它,因为它会给一个简单的问题增加不必要的复杂性)(由提问者的评论添加):


      • 实际上,当道具改变或状态改变时,组件会更新 变化。引用react docs:如果您想在 一个道具改变< /强>,考虑使一个组件<强> < /强> 或者用钥匙代替。完全不受控制将是不可能的 那么选择2


        要触发道具的更改,可以连接标题。 这样,当loca发生时,会通知标头组件
        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);