在路由更改Next.js上更改状态

use*_*781 4 javascript reactjs next.js

嗨,我要在next.js中切换导航,它工作正常,只是我希望在路线更改时再次关闭导航。

例如,如果我在主页上并切换导航,则导航将打开并显示指向“关于”页面的链接。如果单击该链接,则会按预期进入“关于”页面-但导航仍处于打开状态!

我已经尝试了一些方法-我想我想利用onRouteChangeComplete(url),但是我正在努力更新navActive状态。

我的page.js文件:

class Page extends Component {
  state = {
    navActive: false
  };

  toggle = () => {
    this.setState({
      navActive: !this.state.navActive
     });
  };

  render() {
    return (
      <ThemeProvider theme={theme}>
        <StyledPage className="full-page-wrapper">
          <Meta />
          <Header navActive={this.state.navActive} toggle={this.toggle} />
          <PrimaryContent>{this.props.children}</PrimaryContent>
          <GlobalStyle />
        </StyledPage>
      </ThemeProvider>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

然后是我的头文件:

class Header extends React.Component {
  render() {
    return (
      <HeaderSide

        <HeaderToggleBar onClick={() => this.props.toggle()} />

      </HeaderSide>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

因此,应用程序以navActive状态为false开头,单击HeaderToggleBar元素将打开并关闭导航。但是,当路线改变时,我需要关闭导航。我想我可以将click事件放在标题内的导航项上(以便单击切换到新页面),但这似乎有点过头了。

谢谢。

小智 15

我们可以使用路由器事件来处理这个问题。参考: https: //nextjs.org/docs/api-reference/next/router#usage-6

const router = useRouter();
useEffect(() => {
  router.events.on('routeChangeComplete', handleRouteChange)
  return () => {
    router.events.off('routeChangeComplete', handleRouteChange)
  };
}, [router.events]);
Run Code Online (Sandbox Code Playgroud)


小智 7

如果您使用的是功能性 React 组件,您可以这样做:

   const router = useRouter();

   useEffect(() => {
    if (isMenuOpen) {
      setMenuOpen(!isMenuOpen);
    }
  }, [router.asPath]);
Run Code Online (Sandbox Code Playgroud)

  • 推荐使用 `setMenuOpen(state =&gt; !state)` ,或者在这种情况下,从语义上讲,您可能永远对打开菜单不感兴趣,因此为了排除可能翻转切换时的不正确行为,只需:`setMenuOpen(false) )` (3认同)
  • 这似乎在新的应用程序/页面结构中不起作用。它会抛出一个错误并将您发送到[此页面](https://nextjs.org/docs/messages/next-router-not-mounted),告诉您迁移到“next/navigation”挂钩。 (2认同)

Rob*_*Rob 5

看看https://github.com/zeit/next.js/#router-events。在Header组件的ctor中,您应该可以这样:

constructor(props){
  super(props);

  Router.events.on('routeChangeComplete', (url) => {
    props.toggle();
  });
}
Run Code Online (Sandbox Code Playgroud)


Web*_*ber 5

完整示例

使用功能组件。

在 上触发routeChangeStart,因此可以选择在单击后立即为菜单设置动画。

import { useRouter } from 'next/router';

const Menu = () => {
  const router = useRouter();
  const [show, setShow] = useState(false);

  const hide = useCallback(() => {
    setShow(false);
  }, [setShow]);

  useEffect(() => {
    // subscribe
    router.events.on('routeChangeStart', hide);
    
    // unsubscribe
    return () => router.events.off('routeChangeStart', hide);
  }, [hide, router.events]);

  return show ? <div>menu</div> : null
}
Run Code Online (Sandbox Code Playgroud)

管理嵌套(TypeScript)

我在顶层需要类似的东西,但我会分享:

interface ContextProps {
  show: boolean;
  setShow: (show: boolean) => void;
};

export const MenuContext = React.createContext<Partial<ContextProps>>({
  show: false,
  setShow: () => {},
});
Run Code Online (Sandbox Code Playgroud)
  const [show, setShow] = useState(false);

  return (
    <MenuContext.Provider value={{ show, setShow }}>
      {children}
    </MenuContext.Provider>
  )
Run Code Online (Sandbox Code Playgroud)


小智 0

我相信你需要绑定你的回调。您可能还需要添加一个构造函数。这是接受文件上传的项目的片段。

    class Files extends React.Component {
        // define your constructor and call super before setting state vars
        constructor(props){
            super(props);
            this.state = {
                uploadStatus: false
            }
            // Bind your callback
            this.handleUploadImage = this.handleUploadImage.bind(this);
            // set other initial vars if needed
        }

        handleUploadImage(files){
            // do stuff with the files
        }

        render () {
            return (
                <div id="fileContainer">
                    <MyDropzone id={this.props.project._id} onDrop={this.handleUploadImage}>
                        {({getRootProps}) => <div {...getRootProps()} />}
                    </MyDropzone>
                </div>
            )
        }
    }
Run Code Online (Sandbox Code Playgroud)