2

I am trying to figure out how to use next.js routes to populate a sidebar component with route instructions so that when a sidebar option is clicked, the main div is populted with the relevant component.

I can find tutorials showing the CSS for side bar menu items, but I cannot find the next.js route instructions for this task.

So far, I have a Sidebar component with:

function Sidebar({}) {
// I also tried adding href inside the above {} but it didn't work
  // const { me, loading } = useMe()
  const { me, loading: meLoading } = useMe()


  if (meLoading)
    return (
      <Center>
        <Spinner />
      </Center>
    )
  return (
    
    <Flex as="section" minH="100vh" bg="bg-canvas" maxW="100%" p="0">
      <Flex
       
        // px={{ base: '4', sm: '6' }}
      >
        <Stack justify="space-between" spacing="1">
          <Stack spacing={{ base: '5', sm: '6' }} shouldWrapChildren>
            
            <InputGroup>
              <InputLeftElement pointerEvents="none">
                <Icon as={FiSearch} color="muted" boxSize="5" />
              </InputLeftElement>
              <Input placeholder="Search" />
            </InputGroup>
            <Stack spacing="1" >
              <NavButton label="Home"  fontWeight="normal"/>
              <Link href={Library} passHref>
                // I have tried several other versions of this without the passHref, using href="/Library" and a range of other things - but I cant find anything that works - or makes sense as way to put the content in the Container that currently displays lorem ipsum as below

                <NavButton label="Library" aria-current="page" fontWeight="normal" />
              </Link>
              <NavButton label="Tasks"  fontWeight="normal"  />
              
              
            </Stack>
          </Stack>

Then I have another component called Dashbase which should be where the relevant component for the selected sidebar option is displayed (instead of the lorem ipsum).

 const DashBase = () => {
    const isDesktop = useBreakpointValue({ base: false, lg: true })
    const router = useRouter()
    return (
      <Flex
        as="section"
        direction={{ base: 'column', lg: 'row' }}
        height="100vh"
        bg="white"
        mb="100px"
        overflowY="auto"
        minW="100%" 
        px={0}
        mx="0px"
        // minW="120em"
        // margin="auto"
      >
        {isDesktop ? <Sidebar /> : <Navbar />}
  
        <Container py="8" flex="none">
          <Text> lorem ipsum dolor sit amet, consectetur adipiscing lorem ipsum dolor sit amet, consectetur adipiscing
          </Text>
         
        </Container>
      </Flex>
    )
  }

  export default DashBase;
          <Stack spacing={{ base: '5', sm: '6' }}>
            <Stack spacing="1">
              
              <NavButton label="Help"  fontWeight="normal"/>
              <NavButton label="Settings"  fontWeight="normal"/>
            </Stack>
                         <UserProfile
              name={me.firstName + " " +  me.lastName}
              // image="h"
              bio={me.bio} 
            />
          </Stack>
        </Stack>
      </Flex>
    </Flex>
  
  )
}
brc-dd
  • 10,788
  • 3
  • 47
  • 67
Mel
  • 2,481
  • 26
  • 113
  • 273
  • For render a component or a page? – andres martinez Sep 10 '22 at 02:27
  • Component. Currently when i click on library in the sidebar, the url in local host updates to /library - but there isnt a page for library - so I get 404. I want to replace the lorem ipsum with what's in the library component if the library button in the side bar is clicked – Mel Sep 10 '22 at 02:36
  • Do you actually want to route to a different page, or just change some content on the existing page? If you want to change the content displayed within `DashBase`, then you should use state to control what gets displayed. If you want to route to `/library` then add a page for it. – juliomalves Sep 11 '22 at 15:12
  • I want to find a tutorial for state control - so the component in the DashBase changes when a link in the sidebar is clicked – Mel Sep 11 '22 at 21:02
  • @Mel What is the structure of your app? Do you have a serverside code or you are using headless CSM(like contentful?) Also why do you want to populate this routes in a component like that? I mean with next, you can use pages/[[...url.js]], so you build all your routes in server and it is superfast to browse between pages. – Deniz Karadağ Sep 14 '22 at 09:02
  • Hi @DenizKaradağ - I'm not using Contentful. I'm making a react app, with psql db, and using next for routing (or trying to). The reason to do it with components in a div is so I don't have to rerender the sidebar on every page - but maybe that's not a good approach – Mel Sep 15 '22 at 07:49

1 Answers1

2

There are at least two approaches I can think of: wrap both components inside a Context.Provider, and forward props, as you've mentioned.

Let's see how we could implement the latter so that the text inside DashBase is shown/hidden when <NavButton label="Library" /> is clicked. I've omitted bits of code to ease reading and thus understanding.

Our first step is to create a boolean state inside our main component so that we can control when our child element should be hidden or visible.

dashbase.jsx

export const DashBase = () => {
  const isDesktop = useBreakpointValue({ base: false, lg: true })

  // assuming that the component should initially be hidden
  const [showLibrary, setShowLibrary] = React.useState(false)

  // state setter to switch between our `true` and `false` states
  const toggleLibrary = () => setShowLibrary(!showLibrary)

  return (
    <Flex>
      {/* forward the state setter to the `Sidebar` component */}
      {isDesktop ? <Sidebar toggleLibrary={toggleLibrary} /> : <Navbar />}
      <Container>
        {/* and render the text conditionally */}
        {showLibrary && (
          <Text>
            lorem ipsum dolor sit amet, consectetur adipiscing lorem ipsum dolor sit amet, consectetur adipiscing
          </Text>
        )}
      </Container>
    </Flex>
  )
}

We can then pass down our state setter helper toggleLibrary to our Sidebar component.

sidebar.jsx

export const Sidebar = ({ toggleLibrary }) => {
  const { me, loading: meLoading } = useMe()

  if (meLoading)
    return (
      <Center>
        <Spinner />
      </Center>
    )

  return (
    <Stack>
      <Input placeholder="Search" />
      <Stack>
        <NavButton label="Home" />
        <NavButton label="Library" onClick={toggleLibrary} />
        <NavButton label="Tasks" />
        <NavButton label="Help" />
        <NavButton label="Settings" />
      </Stack>
      <UserProfile name={me.firstName + ' ' + me.lastName} bio={me.bio} />
    </Stack>
  )
}

We should now be able to hide/show the <Text>...</Text> component inside our DashBase by clicking on <NavButton label="Library" />.

If we'd like to show/hide the component based on the browser's current location, we could move our state to the Sidebar component and update it dynamically with useEffect:

const router = useRouter()

React.useEffect(() => {
  if (router.pathname.includes('library')) {
    setShowLibrary(true)
  }
  return () => {}
}, [router.pathname])

Would that solve your issue? Let me know how it goes.

Cheers

PREVIOUS ANSWER

A simplistic approach to dynamically create buttons that route to other pages based on some metadata would be:

const paths = ['about', 'home', 'login']

const Example = () => {
  const router = useRouter()
  return paths.map(p => <button onClick={router.push(`/{p}`)}>{p}</button>
}

The above Example component would create three buttons, each pointing to a different path.

Moa
  • 1,456
  • 4
  • 20
  • Hi @Moa, thank you for this. Library is a component, I'm trying to display the content of that component in the main div when a side bar link called 'library' is clicked. I think your example is going to load another page. Maybe I should give up trying do do what I want and just add a sidebar to every page, so I get the same effect. I would like to figure out what I need to do to instruct the router to change the content of the main div, when a link in the side bar is clicked though - it seems logical to me to try to do that – Mel Sep 12 '22 at 20:33
  • Ohh, I see! I think that you might not even need Next's router for this purpose. Some state and a switch should do the trick. I'll update the answer. – Moa Sep 12 '22 at 22:03
  • Thank you so much @Moa - I really appreciate the explanation of your steps. One day, I'll pay this forward - i'm 10 years into to trying to learn and I'm still in the deep fog of near constant confusion – Mel Sep 16 '22 at 23:39