How Can I conditionally wrap this react component - reactjs

I am just wondering on how can I avoid duplicating this code when I am conditionally rendering a component.
What I have so far is a navbar component that is connected to redux and it gets state of (isAuth or not) if it's it would render the div with the logout() else it would render the div with login().
Now this approach is not quite good and it's repetitive. I have come across this https://blog.hackages.io/conditionally-wrap-an-element-in-react-a8b9a47fab2 which basically allows you to conditionally render components without duplicating the code but Unfourtnely I was unable to get my head around it. Sorry, I am just learning to react at the moment.
If you please tell me how to use this or if there is an alternative way that i can try that would be very helpfull
Thanks
function Navbar({ isAuth, logOut }) {
if(isAuth) {
return(
<div className="navbar">
<a> link A</a>
<a> link B</a>
<a> link C</a>
<a> link D</a>
<button onClick={() => logOut()} > Logout </button>
</div>
)
}
return (
<div className="navbar">
<a> link A</a>
<a> link B</a>
<a> link C</a>
<a> link D</a>
<button> Login </button>
</div>
)
}
const mapStateToProps = ({ login }) => {
return {
isAuth: login.isAuthenticated
};
};
export default connect(
mapStateToProps,
{ logOut }
)(Navbar);

Just make the button render conditional;
function Navbar({ isAuth, logOut }) {
return(
<div className="navbar">
<a> link A</a>
<a> link B</a>
<a> link C</a>
<a> link D</a>
{isAuth ? <button onClick={() => logOut()} > Logout </button> : <button> Login </button>}
</div>);
}
}
const mapStateToProps = ({ login }) => {
return {
isAuth: login.isAuthenticated
};
};
export default connect(
mapStateToProps,
{ logOut }
)(Navbar);
You can place basic conditions within render/returns wrapped in curly braces - {}. Basically if isAuth is truthy render logout, otherwise login.

Related

Scrolling the page up in React

In my component, i wanna scroll the page up when the user click on Link Component witch will change the url and therefore what user sees.
import { Link } from "react-router-dom";
const RelatedMovieItem = props => {
const movie = props.movie;
return (
<div className="card" style={{width: "18rem",marginTop: "10px", padding: 0, marginLeft: "10px"}}>
<img src={movie.imageUrl} className="card-img-top" alt={movie.name} />
<div className="card-body">
<h5 className="card-title">{movie.name}</h5>
<p className="card-text">{movie.description}</p>
<Link to={`/movies/${movie.id}`} className="btn btn-primary">Go to details</Link> //once this clicked i want to scroll the page up
</div>
</div>
);
};
export default RelatedMovieItem;
How to do so?
if every route changes you want to scroll top you can do it using <ScrollToTop> passing children down the tree like that.
<BrowserRouter>
<ScrollToTop>
<Switch>
// your route
</Switch>
</ScrollToTop>
</BrowserRouter>;
And create component ScrollToTop.js
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export default function ScrollToTop({children}) {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return <>{children}</>;
}
You can make use of window.scrollTo(0,0) by passing it to the onClick attribute.
This way your page will scroll to the top left whenever you click on <Link />.
<Link
to={`/movies/${movie.id}`}
className="btn btn-primary"
onClick={() => window.scrollTo(0, 0)}
>
Go to details
</Link>
you can use a reference and attach it to the component you want to scroll to.
Then onclick you can call ref.current.scrollIntoView()

Navigate to an external website on button Click

In my app users click on button and navigate to external website. This external website is picked dynamically based on a form they fill.
Here, on clicking the button is not working.
What I am doing wrong here?
const handleLink1 =()=>{
<Link
to={{
pathname: `${data.url}`
}}
target="_blank"
>
{' '}
</Link>
}
<button onClick={handleLink1} className="btn-primary"> {data.buttonName}</button>``
Your handleLink1 should be like this.
const handleLink1 = () => {
window.open(data.url);
}
<button onClick={handleLink1} className="btn-primary"> {data.buttonName}</button>
I didn't really understand your code, but I don't think returning <Link> from click handler function is the correct solution. <Link> from react-router will only provide you ways to navigate around routes of your app.
To navigate to external url, you can either make use of <a> tag or window.location.href or window.open() .I believe you meant to do
const handleLink1 = () => {
window.open(data.url, '_blank');
}
<button onClick={handleLink1} className="btn-primary"> {data.buttonName}</button>
or instead of button directly use
<a
class='btn-primary'
href=`${data.url}`
target='_blank'
rel="noopener"
aria-label='Github'
>
{data.buttonName}
</a>
correct me if I'm mistaken :)
Could you provide the code for handleLink1?
Anyways, if handleLink1 is anything like handleLink2, your mistake is creating a Link component in the event handler. It'll never be rendered. What you have to do instead, is wrap your button component in the Link component, like so:
<Link
to="somewhere"
>
<button className="some-class">Click me to go somewhere!</button> //No need for the onClick event handler.
</Link>
Edit
Maybe the below will help clarify:
import { useState } from "react";
import { Link } from "react-router-dom";
const IllNeverRender = () => {
return <p>Nope</p>;
};
const IllRender = () => {
return <p>Yep</p>;
};
export default function LinkButton() {
const [Component, setComponent] = useState();
const renderOnClickWrong = (event) => {
<IllNeverRender />; // This component isn't returned from the handler, nor would it render if it was returned.
};
const renderOnClickRight = (event) => {
setComponent(<IllRender />);
};
return (
// Only components returned from a functional component, or a React Component's render method, gets rendered.
<div>
<Link to={{ pathname: "/somewhere" }}>
<button>Go somewhere!</button>
</Link>
<button onClick={renderOnClickWrong}>Go nowhere.</button>
<button onClick={renderOnClickRight}>Render something.</button>
{Component}
</div>
);
}
let home = "https://explorer.solana.com/tx/" + url;
window.open(home);
This is the perfect source code.

JSX onClick event seems to be clicked on default

I think I am doing something stupid. I have some code and can't figure out why its not working how I expect it to.
I expect the terminal to log to the terminal when the button / link is clicked but it seems to do it regardless
Code below
import React, { Component } from 'react'
import DataExample from './dataExample'
export default class home extends Component {
state = {
name:"Joy",
place:"nirvana"
}
consoleLog = (e) =>{
return console.log("just clicked")
}
render() {
return (
<div>
<h3>This is my homepage that contains components</h3>
<a href="#" onClick={this.consoleLog("link clicked")}>My Button</a>
</div>
)
}
}
Actual result shows the console.log proir to my clicking button
Currently you are calling the this.consoleLog() in the code instead of passing it.
This should work:
<a href="#" onClick={() => this.consoleLog("link clicked")}>My Button</a>
consoleLog() is calling on the render
return (
<div>
<h3>This is my homepage that contains components</h3>
<a href="#" onClick={() => this.consoleLog("link clicked")}>My Button</a>
</div>
)
}

React - use button for redirect link

I'm new to React so sorry if this is too basic.
I am trying to add a button in my app to redirect it to Spotify.
This is how I'm trying to do it, so far.
class Spotify extends Component {
constructor () {
super()
this.handleClick = this.handleClick.bind(this)
}
handleClick () {
console.log('Success!')
}
render () {
return (
<div className='button__container'>
<button className='button' onClick={this.handleClick}>
Link your Spotify account
</button>
</div>
)
}
}
export default Spotify;
Now, what is the best way of linking the above button to:
I think you're looking for something like this:
class Spotify extends Component {
render () {
return (
<div className='button__container'>
<a className='button' role="button" href="http://someurl.com">
Link your Spotify account
</a>
</div>
)
}
}
export default Spotify;
If your component doesn't require state, consider refactoring the above code into a stateless component like so:
export const Spotify = () => (
<div className='button__container'>
<a className='button' role="button" href="http://someurl.com">
Link your Spotify account
</a>
</div>
);
If you are just trying to display a link, an anchor tag will work just fine. You can add target="_blank" to your anchor tag to have it open in a new tab.

react-bootstrap breadcrumb with react-router-dom

I'm trying to use react-bootstrap breadcrumb as below.
<Breadcrumb>
<Breadcrumb.Item href="#">Home</Breadcrumb.Item>
<Breadcrumb.Item><Link to={"/products"}>Products</Link></Breadcrumb.Item>
<Breadcrumb.Item active>{productName}</Breadcrumb.Item>
</Breadcrumb>
As you can expect, products Link will render anchor tag inside another anchor tag, which is invalid markup. But Home creates a simple anchor tag instead of react's Link making the page to reload, making it unusable.
What's the solution for this? Unfortunately, there's no mention of this in react-bootstrap doc. (link)
I would probably use react-router-bootstrap, but if you don't want to include it as a dependency, you can apply the link by hand using the now available linkAs and linkProps Breadcrumb params. For instance:
<Breadcrumb.Item linkAs={Link} linkProps={{ to: "/path" }}>
My item
</Breadcrumb.Item>
This approach is interesting especially if you are using just the "as" attribute with other components like Button or NavLink.
This nicely works and it does not refresh the whole page, only what's needed to change
import { Breadcrumb } from "react-bootstrap";
import { Link } from "react-router-dom";
export const SiteMap = ({ hrefIn }) => {
const items = [
{ href: "/dictionaries", name: "Dictionaries" },
{ href: "/antonyms", name: "Antonyms" },
];
return (
<Breadcrumb>
{items.map((item) =>
item.href === hrefIn ? (
<Breadcrumb.Item active>{item.name}</Breadcrumb.Item>
) : (
<Breadcrumb.Item linkProps={{ to: item.href }} linkAs={Link}>
{item.name}
</Breadcrumb.Item>
)
)}
</Breadcrumb>
);
};
I ended up dropping react-boostrap and doing it 'by hand':
const Breadcrumbs = ({ breadcrumbs }) => (
<ol className="breadcrumb">
{breadcrumbs.map((breadcrumb, index) => (
<li key={breadcrumb.key}>
<NavLink to={breadcrumb.props.match.url}>
{breadcrumb}
</NavLink>
</li>
))}
</ol>
);
It works for me if I wrap <Breadcrumb.Item> into the <LinkContainer>.
Now outer Breadcrumb "My applications" which points to /applications URL redirects my app with react-router to the applications page.
I tested this with react-bootstrap v0.32.4 https://5c507d49471426000887a6a7--react-bootstrap.netlify.com/components/breadcrumb/
I got <LinkContainer> from react-router-bootstrap package: https://github.com/react-bootstrap/react-router-bootstrap
I saw "the wrapping" here before, though I don't generate breadcrumb in a loop: https://github.com/react-bootstrap/react-router-bootstrap/issues/141#issue-122688732
import { LinkContainer } from 'react-router-bootstrap';
// and then in the render function
<Breadcrumb>
<LinkContainer to="/applications" exact>
<Breadcrumb.Item>My applications</Breadcrumb.Item>
</LinkContainer>
<Breadcrumb.Item active>My First Applicaton</Breadcrumb.Item>
</Breadcrumb>
Here I have passed onClick to Breadcrumb.Item to handle navigation with the help of
import { withRouter } from "react-router-dom";
Here is the sample:
const RenderBreadcrumb = ({ breadcrumbInfo, history }) => {
const handleRedirect = (url) => {
history.push(url);
}
return (
<Breadcrumb>
{ map(breadcrumbInfo, (item) => {
if(item.isActive) {
return (<Breadcrumb.Item active>{item.text}</Breadcrumb.Item>);
}
return (<Breadcrumb.Item onClick={() => { handleRedirect(item.link); }}>{item.text}</Breadcrumb.Item>);
})}
</Breadcrumb>
)
}
export default withRouter(RenderBreadcrumb);
Bootstrap.Item internally uses SafeAnchor which allows you to not use a link if you don't want to.
Using the as prop you can modify what tag is used (a by default). For example you can pass:
<Bootstrap.Item as="div" />
And it will use a div tag for presenting the item.

Resources