How to create dynamic hyperlink (href) using React? - reactjs

Completely new to React, so please forgive my ignorance.
Using ReactStrap for this example. I'm attempting to define {url} dynamically, to where it's defined under src/components in its own jsx file:
const NavLink = ({ url },{ children }) => (
<RSNavLink href={url}>
{children}
</RSNavLink>
);
but when I call the component elsewhere, I can insert whatever hyperlink I'd like:
<NavLink href="/">Hello, World!</NavLink>
I'm not able to find documentation specific to what I'm looking for (or at least, I may not be searching for the right thing). If anyone could point me in the right direction, it'd be much appreciated.

In NavLink Component you are wrongly destructing props value and give exactly same name as props. change it like this
const NavLink = ({ url ,children }) => (
<RSNavLink href={url}>
{children}
</RSNavLink>
);
<NavLink url="#">
Hello World
</NavLink>
check demo in stackblitz

Related

How to make Link from react-router-dom work further inside the application?

I have a <HashRouter> wrapping the components which holds the <Link> components, however, I still get the error Error: Invariant failed: You should not use <Link> outside a <Router>. Is there some hierarchy that says you have to have the Links on a higher level than I have? I have the <Link>
inside a dropdown.
Something like my app is:
<HashRouter>
<ComponentA>
<ComponentB>
<Link to="/my-path"/>
</ComponentB>
</ComponentA>
</HashRouter>
EDIT:
What I am doing is adding a <Link> inside a custom option inside a dropdown which I have gotten from a library. It says I can add custom elements into my dropdown options. The dropdown I am making is complex with buttons inside it, and I want to link to one place if you click the title. There is where the Link comes in. When I add the Link there, the error message appear, but not when I add the Link directly to the component which is using the dropdown. This is how I have the component, which is not working. This is just mocked data, the data I use are calculated inside a .map:
const CustomLink = () => <Link to="/some-path">Title of link</Link>;
const data = [{
selected_key: 'id1',
content: [<CustomLink />, <CustomButton />]
},
...
]
return <DropdownFromLibrary data={data} />;
I want/need to add the components inside a array, but the above example does not work. This below do work, to have the Link inside the same component as the Dropdown, but is not what I want, since I need to calculate new path to every option:
return (
<>
<CustomLink />
<DropdownFromLibrary data={data} />
</>
);
SOLUTION
import { useHistory } from 'react-router-dom';
...
const history = useHistory();
const CustomLink = ({ id, title }) => <div onClick={() => history.push(`/some-title/${id}`)}>{title}</div>
const data = [{
selected_key: 'id1',
content: [<CustomLink />, <CustomButton />]
},
...
]
return <DropdownFromLibrary data={data} />;
You have an error because the Link has to go inside the < componentB> . I mean inside componentB's function. Wrap ur return elements inside the Link.

How to create a button that opens a new page with the option to return back to previous page [ReactJS

Right below the page you see a 'back to log' button. If someone clicks on that it will return to the left page. So in order to do so I thought using react router will do the job. But not sure how to fix that.Is there someone who can help me to point me to the right direction. Keep in mind that it will not open a new tab!
Link to working snippet to understand the bigger picture of my app. CodeSandBox snippet here
return (
<div>
{info.map((show: any) => {
console.log(show.show)
return (
<div key={show.show.id}>
<ReactMarkdown source={show.show.name}/>
{show.show.image && <img src={show.show.image.medium}/>}
{show.show.genres.map((showGenre: string, index: number) => {
return (
<div key={index}>
<ReactMarkdown source={showGenre}/>
</div>
)
})}
<div>
<Router>
<ul>
<li>
<Link to="/">See deta</Link>
</li>
</ul>
</Router>
</div>
</div>
)
})}
</div>
)
Check out this working example (I placed notes in each file):
https://codesandbox.io/s/modest-panini-hkzlv?file=/src/App.js
Overview:
there are several ways to do this
my suggestion is to use the history npm and create a history.js file
you will also need to use Router from react-router-dom
in your parent component, or in a Context provider, you can store your state
in the parent component, use react-router-dom Switch and Route to place routes
depending on implementation, conditionally render show route for async state update
in your search component, place all your Links using react-router-dom
on click Links should also update app's state of your specific selection
this selection gets passed to the show route/component
in the show component attach an on click that uses history.goBack and resets state
this might help you:
this.props.history.goBack();
it goes back to prev page

How to get the current url path using hook router in react?

I'm new to react and react hooks. I'm using hookrouter package and I tried to googling about the question, but didn't find much about it.
What I want?
I'm trying to get the current url path. For e.g. for https://example.com/users/temp, I want to get /users/temp.
Any help will be appreciated. Thanks in advance!
I finally found on github doc.
import {usePath} from 'hookrouter';
const PathLabel = () => {
const path = usePath();
return <span>Your current location: {path}</span>;
}
I wanted to let you know there's also a generic way to return the path using Javascript, in case you're not using hookrouter on a different project
Just invoke window.location.pathname
I'm using it for setting active className for links in my Nav component based on which route the client is on using a ternary expression. Example:
const NavList = props => {
return (
<NavContainer>
<ul>
{routes.map(({ key, href, label }) => (
<A href={href} key={key} className='route-link'>
<li
className={href === window.location.pathname ? 'active' : null}
>
{label}
</li>
</A>
))}
</ul>
</NavContainer>
);
};

Gatsby page in page

I'm using gatsby js and trying to figure out how to have a page level side bar with Gatsby links that render a new component inside a div in the same page I can do this using react-router-dom but in Gatsby all I can find is how to create blog posts which is driving me nuts as every tutorial I find is the same blog post.
Here is my layout page /layouts/index.js
export default ({ children }) => (
<div id="layout">
<header>
<h3>Header</h3>
<MainNav />
</header>
{children()}
</div>
)
About Page
/pages/about.js
export default ({ location, match }) => {
console.log('location = ', location, 'match = ', match );
return (
<div id="about">
<SideBar />
<div id="content">
// . add child template or component for link clicked in sidebar
</div>
</div>
);
};
What I'm trying to do is when a user clicks on a link in the side bar stay on about but render a new component or template based on the gatsby-link clicked in the about sidebar.
The About SideBar component
/components/about/side-bar.js
const SideBar = () => {
return (
<div id="side-bar">
{/* <li><Link to='/about?sort=name'>work</Link></li> */}
<li><Link to="/about/work">work</Link></li>
<li><Link to='/about/hobbies'>hobbies</Link></li>
<li><Link to='/about/buildings'>buildings</Link></li>
</div>
)
}
Problem with the links above, they are trying to go to a new page called.
/about/work
This is not what I'm trying to do. Again I'm trying to make it stay on about but render a new component inside the content div.
Please help gatsby is so all over the place as far as docs goes. ok maybe its just me and not getting the docs clearly.
Thanks
UPDATE:
I tried adding a page suing createPage which works for me kind of but it doesn't pass the match.params id
gatsby-node.js
exports.createPages = ({ boundActionCreators }) => {
const { createPage } = boundActionCreators;
const myComponent = path.resolve('src/pages/about/index.js');
createPage({
path: '/about/:id',
component: myComponent
})
}
After a long time of trying to understand Gatsby and I can say I still don't as its docs are vast and not very clear. But once I started to look at the node-apis and onCreatePage it gave me some ideas. This is what the docs literally say.
onCreatePage
Called when a new page is created. This extension API is
useful for programmatically manipulating pages created by other
plugins e.g. if you want paths without trailing slashes.
So the only part in here that gives me a hint of this might be the key to helping me is this line. useful for programmatically manipulating pages created by other
plugins
Anyway this got me writing some code at least. Then about 3 hours later I found a plugin that was doing exactly what I was trying to do with this method. The plugin is called gatsby-plugin-create-client-paths key here is client-paths!!!!!
This makes life worth living! So in my case above I just wanted to be able to use Gatsby's router ( which is just react-router-dom behind the scenes), to pass me and id or value to routers match.params object. It still doesn't but what it does do is checks for any path after a prefix like /folder/ in my case '/about/work and recreate the page with a template component (in my case keep using pages/about/index.js), which is my template. Now that we have about/index.js rendering for ever link after /about/ then we can use some internal switch statement to handle the location that is been passed to /about/index.js. Still don't get match.params update but I do get props.location.pathname; which allows me to extract everything after the prefix to use in a switch statement to render my specific components based on the routes pathname. Enough rabbiting on here is a rough solution to show as an example.
So add the plugin as an npm install.
open up gatsby.config.js and add the below code to the exports.
module.exports = {
plugins: [
{
resolve: `gatsby-plugin-create-client-paths`,
options: { prefixes: [`/about/*`] },
},
]
}
Then in my main about page pages/about/index
import React from "react";
import SideBar from '../../components/about/side-nav';
export default (props) => {
const { pathname } = props.location;
var n = pathname.lastIndexOf('/');
var pageId = pathname.substring(n + 1);
const page = () => {
switch(pageId){
case '':
return (
<div>Work Page</div>
);
case 'work':
return (
<div>Work Page</div>
);
case 'hobbies':
return (
<div>Hobbies Page</div>
);
case 'buildings':
return (
<div>buildings Page</div>
);
}
}
return (
<div id="about">
<SideBar />
<div id="content">
{page()}
</div>
</div>
);
};
Then in my sidebar I call it like this.
<li><Link to="/about/work">work</Link></li>
<li><Link to='/about/hobbies'>hobbies</Link></li>
<li><Link to='/about/buildings'>buildings</Link></li>
Hopefully this will help someone else out. After all this I'm starting to really question the bulk of gatsby especially with docs not been very clear. Based on the response to my question I guess not many people in stackoverflow's community are using Gatsby which is worrying when you need help. It does look like Gatsby's github community is very helpful but that should be for bug issues and not for questions like mine, but encouraging to see.
Hope this helps someone.

What does the tag attribute in Reactstrap do?

I have a navbar using reactstrap and wanted to incorporate react-router.
After a failed attempt I have found the solution here.
However I don't understand the syntax:
I have a <NavLink> from React-Router
and a navbar from Reactstrap.
Instead of wrapping the Reactstrap's inside React-Router's (Which throws a warning):
<NavLink to="/">
<NavbarBrand className="mx-auto" to="/" tag={ NavLink }>
My Site
</NavbarBrand>
</NavLink>
This is the syntax:
<NavbarBrand className="mx-auto" to="/" tag={ NavLink }>
My Site
</NavbarBrand>
What is the tag attribute? What does it do?
Thanks all!
When you render NavbarBrand component you have an option to render individual links as default a tag (HTMLAnchorElement) or you can provide your own custom component to render navigation items.
In this case it's convenient to pass NavLink as a tag so that nav items are rendered with NavLink. This is what you need.
Looking into respectful source code for NavbarBrand you see this in render method:
return (
<Tag {...attributes} className={classes} />
);
So if you don't pass tag prop to NavbarBrand then above Tag is going to be a tag.
The docs aren't hugely clear on this, but all can be revealed by looking at the source:
const NavbarBrand = (props) => {
const {
className,
cssModule,
tag: Tag,
...attributes
} = props;
const classes = mapToCssModules(classNames(
className,
'navbar-brand'
), cssModule);
return (
<Tag {...attributes} className={classes} />
);
};
NavbarBrand effectively just instantiates whatever tag/component you give it with the appropriate style classes applied, and passes the rest of the props on to it.
I've checked the documentation and there was no description of what tag does, but PropTypes validate whether it is a string or a function
My reasoning based on examples is this:
<Breadcrumb tag="nav">
<BreadcrumbItem tag="a" href="#">Home</BreadcrumbItem>
<BreadcrumbItem tag="a" href="#">Library</BreadcrumbItem>
<BreadcrumbItem tag="a" href="#">Data</BreadcrumbItem>
<BreadcrumbItem active tag="span">Bootstrap</BreadcrumbItem>
</Breadcrumb>
it accepts the name of an HTML tag or a React Component to be used as a wrapper.

Resources