Reputation: 2685
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>
)
}
Upvotes: 4
Views: 4541
Reputation: 1566
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.
Upvotes: 2