Controlling the sidebar of a responsive layout and updating the title component based on current route in React.js

Viewed 190

I have two years of experience with React and RN but it's the first time I have to plan a web app from scratch.

Here's what the layout looks like:

Layout design

And the structure of App.js. I'll add in Redux or another store provider later.

function App() {
  const [isMobile, setIsMobile] = useState(false);
  const width = useWindowWidth();

  useEffect(() => {
    setIsMobile(width < theme.mobileWidthLimit);
  }, [width]);

  return (
    <ThemeProvider theme={{ isMobile, ...theme }}>
      <BrowserRouter>
        <Layout isMobile={ isMobile }>
          <Pages/>
        </Layout>
      </BrowserRouter>
    </ThemeProvider>
  );
}

I'm deciding whether the window is too narrow for desktop UI or not, and based on that I pass the isMobile prop to the theme provider of Styled Components and also the main layout.

Here's what my layout looks like:

const Layout = ({ children, isMobile }) => {
  const [sideBarOpen, setSideBarOpen] = useState(!isMobile);
  // Navigation side bar will be closed when user navigates
  const location = useLocation();
  useEffect(() => setSideBarOpen(false), [location.key]);
  // TODO improve title updation
  const title = ((path) => {
    switch (path) {
      case '/trip':
        return 'Your trips';
      case '/trip/new':
        return 'New trip';
      default:
        return 'View trip';
    }
  })(location.pathname);

  return (
    <OuterDiv>
      <MenuButton onClick={ () => setSideBarOpen(!sideBarOpen) }/>
      <NavSideBar isOpen={ sideBarOpen }/>
      <InnerDiv isClosed={ sideBarOpen }>
        <Header>
          <h1>{ title }</h1>
        </Header>
        <Content>
          { children }
        </Content>
      </InnerDiv>
      { !isMobile && <InfoSideBar/> }
    </OuterDiv>
  );
};

Here's how sidebar and content replace each other based on isMobile and sideBarOpen.

sidebar:

display: ${(props) => props.theme.isMobile && !props.isOpen ? 'none' : 'flex'};

inner div (wrapping the content and header):

display: ${(props) => (props.theme.isMobile && props.isClosed) ? 'none' : 'flex' };

I hope I managed to give you a good overall idea of what the app looks like. Now, the two things that have been bugging me were these:

  1. Whether the sidebar will be visible or not depends on isMobile and sideBarOpen. I think what I did with isMobile is a reliable and good solution, but I feel like setSideBarOpen could be simplified. I change its value when user taps on the hamburger menu button to the opposite of its current value, and assign a false value when there is some sort of attempt to navigate within the app. I couldn't find a better way to close the menu when user taps on a link from the menu on the sidebar. React Router detects the change, and so does the app. Could it be improved?

  2. I update the title using a switch case statement, deducing what it will be based on the react-router's current path. There has to be a better way to do this, right? Please note that the header is outside the BrowserRouter component of react-router.

0 Answers
Related