In react I've used to push with history prop like this :
<button onClick={() => props.history.push('/someurl')} >
I tried this way but it doensn't work :
import { navigate } from '#reach/router';
<button onClick={ () => navigate(`/`);} > Navigate < / button>
Error :
Gatsby.js development 404 page
There's not a page yet at /
I've also tried this url :
navigate(`localhost:8000/`);
But it throws this error in the console :
Failed to launch 'localhost:8000/' because the scheme does not have a registered handler.
It says the page doesn't exist but it does and I've checked it by putting the same url in browser and it does exist .
How can I push something to url in gatsby ?
Instead of importing navigate from #reach/router, use the Gatsby-provided wrapper:
import { navigate } from "gatsby"
const HomeButton = () =>
<button onClick={() => navigate("/")}>
Homeward!
</button>
If you want to change the URL without keeping the previous page in history you can also pass the second argument an options object with replace set to a truthy value. E.g.:
const HomeButton = () =>
<button onClick={() => navigate("/", { replace: true })}>
Homeward!
</button>
Related
I am trying to write a function that sets the current location to the route that was just clicked. However, as you can see, it gives me the url of the page I was on WHEN I clicked the button, not the page of path of the button itself. What should I use instead of window.location.pathname?
const setLocation = () => {
console.log(window.location.pathname);
setCurrentLocation(window.location.pathname);
};
<Link onClick={() => setLocation()} to="/today" className="btn btn-primary btn-sm">
<Link onClick={() => setLocation()} to="/upcoming" className="btn btn-primary btn-sm">
Why are you storing this to the state ?
ReactRouter has a hook useLocation https://v5.reactrouter.com/web/api/Hooks/uselocation in which you can take .pathname of any pushed path to history.
If you really want to store location by yourself pass on the route value in to as a param in setLocation function or create a component that wraps the Link component and does store location : )
ie:
<Link onClick={() => setLocation("/upcoming")} to="/upcoming" className="btn btn-primary btn-sm">
code is like ===>
onClick={
(e)=>console.log(e.target.href)
setLocation(e.target.href)
}
const setLocation = (path) => {
console.log(window.location.pathname);
setCurrentLocation(window.location.pathname+path);
};
Using React, Next.JS and React-Bootstrap
So, i'm trying to just create a dismissable alert, like in the React-Bootstrap documentation, however, it would not close for me. Upon further inspection (that's what the console.logs arefor), i noticed that my Alert component is lauching "onClose" immediately upon being opened. That's a problem. Further more, i've also noticed that no matter what i pass as "onClosing", it reads in the console as "undefined", rather than outputting the function i sent it. This is made further weird, by the fact that just two lines down, im sending the same function, with opposite state to another component (where i signal the website to open the alert), and it's working completely fine. I've been at this for a couple hours now, and i'm pretty stuck. Any help would be appreciated!
My state variable at init
const [showAlert, setShowAlert] = useState(false)
Here's my Alert component
import {Alert, Button, ButtonGroup, ButtonToolbar, Collapse} from 'react-bootstrap'
import PropTypes from 'prop-types'
const MyAlert = ({onClosing, alertHeading, alertText, alertVariant, methodToExecute, buttonText}) => {
console.log(onClosing)
return (
<Alert variant={alertVariant} onClose={()=> onClosing} dismissible style={{margin:'1rem'}}>
<Alert.Heading>{alertHeading}</Alert.Heading>
<p>{alertText}</p>
<ButtonToolbar>
<ButtonGroup style={{margin:'.5rem .5rem .5rem 0'}}>
<Button variant={alertVariant} onClick={()=> {methodToExecute!=undefined ? methodToExecute : onClosing}}>{buttonText}</Button>
</ButtonGroup>
<ButtonGroup style={{margin:'.5rem'}}>
<Button variant={alertVariant} onClick={() => onClosing}>Close</Button>
</ButtonGroup>
</ButtonToolbar>
</Alert>
)
}
MyAlert.defaultProps = {
buttonText: 'OK'
}
/* MyAlert.propTypes = {
onClosing: PropTypes.func
} */
export default MyAlert
And here's my Implementation of it
{showAlert ? <MyAlert onClosing={() => setShowAlert(false), console.log("closing")} alertVariant="danger" alertHeading="Test Alert" alertText="This is just a test alert."/> : ''}
The other component implementation i'm sending that setShowAlert to
<ParameterList onRandomList={() => randomListOfInstruments()} onNewList={ () => addNewInstruments()} onClear={() => setShowAlert(true)}></ParameterList>
Your usage of MyAlert component is probably the issue here:
{showAlert ? <MyAlert onClosing={() => setShowAlert(false), console.log("closing")} alertVariant="danger" alertHeading="Test Alert" alertText="This is just a test alert."/> : ''}
You are passing a value to the onClosing, alertHeading, alertText, alertVariant props of MyAlert, while the actual props of MyAlert are:
{onClosing, alertHeading, alertText, alertVariant, methodToExecute, buttonText}
Among those, you also have methodToExecute, which you are using as a condition when loading your alert:
<Button variant={alertVariant} onClick={()=> {methodToExecute!=undefined ? methodToExecute : onClosing}}>{buttonText}</Button>
Basically, since your methodToExecute is always undefined, this button will always activate onClosing when clicked.
The solution is to add all the necessary props when using MyAlert, or at least include methodToExecute function in the props you pass to it, so your button will bind that to the onClick function instead.
As for onClosing which you are passing as a prop to MyAlert, you also need to fix that, because you are calling two functions separated by comma ',' on its implementation:
onClosing={() => setShowAlert(false), console.log("closing")}
The proper implementation would be:
onClosing={() => {
setShowAlert(false);
console.log("closing");
}}
I am developing a Certificate Management System where after all the processes have been done, the user may print a certificate.
I am struggling to implement such that upon clicking the print button, a new tab will open containing the ready to print HTML certificate so that the user will only CTRL + P to have the certificate printed.
How do i render my react certificate component in a new window? Such that i would only pass the props which are the data to be put into the certificate e.g., name, date etc.. like <Certificate name={john} />
I have tried implementing the npm react-new-window but it does not work with
<Button onclick={() => {
<NewWindow>
<CertificateComponent>
</NewWindow>
}}
>
PRINT BUTTON
</Button>
I have looked into react portals but most use cases are for Modals, which is where my "PRINT" button is rendered.
Sorry for the bad english/explanation. Thank you!
New Solution based on CreatePortal
import React, { useEffect, useCallback, useMemo, useState } from "react";
import { render, createPortal } from "react-dom";
const App = () => {
const [isOpen, setOpenState] = useState(false);
const open = useCallback(() => setOpenState(true));
const close = useCallback(() => setOpenState(false));
return (
<div>
<h1>Portals in React</h1>
<button onClick={open}>Open</button>
<button onClick={close}>Close</button>
{isOpen && (
<NewWindow close={close}>
Example <button onClick={close}>Close</button>
</NewWindow>
)}
</div>
);
};
const NewWindow = ({ children, close }) => {
const newWindow = useMemo(() =>
window.open(
"about:blank",
"newWin",
`width=400,height=300,left=${window.screen.availWidth / 2 -
200},top=${window.screen.availHeight / 2 - 150}`
)
);
newWindow.onbeforeunload = () => {
close();
};
useEffect(() => () => newWindow.close());
return createPortal(children, newWindow.document.body);
};
render(<App />, document.getElementById("root"));
There can be multiple approaches for this.
Approach 1:
Create a new route and map the certificateComponent to it, make sure it doesn't have any authentication or any dependency to it.
Store the required data for certificateComponent either in session storage or local storage.
When the user clicks on print button, redirect the user to this new route using window.open("http://localhost:port/newroute").
In certificateComponent read the values stored in session/local storage and map it accordingly.
Approach 2:
Make the certificate component as an overlay which occupies the entire screen which shows up when the user click on print button.
If any UI elements need to be hidden, you can do something as shown below:
printFn = function() {
// show the certificate component
// hide the ui elements not required
// window.print()
}
This worked for me
const myWindow: any = window.open('','', 'height: 500;width:500');
ReactDOM.render(<Yourcomponent prop={propValue} /> , myWindow.document.body);
myWindow.document.close();
myWindow.focus();
myWindow.print();
myWindow.close();
I am having a Next JS app where there are very simple two pages.
-> Home page
import Header from "../components/header";
const handleForm = () => {
console.log("trigger");
};
export default () => (
<>
<Header />
<h1>Home</h1>
<form onSubmit={handleForm}>
<input type="text" placeholder="Username" />
<input type="password" placeholder="Password" />
<button type="submit"> Login </button>
</form>
</>
);
-> About page
import Header from "../components/header";
export default () => (
<>
<Header />
<h1>About us</h1>
</>
);
Requirement:
-> Home page has a login form
-> If user started typing in any of the fields then without submitting the form, if he tries to move to About us page then a warning needs to be displayed something similar like beforeunload_event.
I am not sure how we can handle it in react as I am new to it.. Kindly please help me to handle a alert if user trying to navigate to other url while editing the form fields..
From my understanding, you can achieve your goal by listen the event routeChangeStart as then throws exception in case of rejecting to move the target url.
I forked above codesandbox and created a simple demo based on your idea which doesn't allow to switch page in case of username having value (form is dirty).
Here is the general idea:
import router from "next/router";
export default () => {
// Assume this value holds the status of your form
const [dirty, setDirty] = React.useState();
// We need to ref to it then we can access to it properly in callback properly
const ref = React.useRef(dirty);
ref.current = dirty;
React.useEffect(() => {
// We listen to this event to determine whether to redirect or not
router.events.on("routeChangeStart", handleRouteChange);
return () => {
router.events.off("routeChangeStart", handleRouteChange);
};
}, []);
const handleRouteChange = (url) => {
console.log("App is changing to: ", url, ref.current);
// In this case we don't allow to go target path like this
// we can show modal to tell user here as well
if (ref.current) {
throw Error("stop redirect since form is dirty");
}
};
return (
// ...
)
}
The link codesandbox is here https://codesandbox.io/s/react-spring-nextjs-routes-forked-sq7uj
I am working on gatsby. I need to go back to privious page/link as I used to do with reactjs.
<a onClick={() => this.props.history.goBack}>
<button type="button" className="close_tab">
<img src={Close} alt="" />
</button>
</a>
How can I do this using gatsby?
Use navigate(-1):
import React from "react";
import { navigate } from "gatsby";
export default function GoBack() {
return (
<Button onClick={() => navigate(-1)}>
Go Back
</Button>
);
}
Edit: Since reach-router#1.3.0, you can now simply call navigate(-1) to go back. Manually update reach-router in your Gatsby project if it's not yet updated. Thanks #nathan in the comment for the tip.
Edit: Ah alright, I've just realized this.props.history.goBack is a react-router thing. Gatsby doesn't use react-router, but reach-router under the hood and it doesn't have the history props or the goBack method. There's a issue requesting to add this, but wasn't implemented. You'd have to use browser's own history object as I suggested below.
import React from 'react'
const BackButton = React.forwardRef(
({ children, ...props }, ref) => {
const onClick = e => {
e.preventDefault()
history.back()
}
return (
<a {...props} ref={ref} href="#" onClick={onClick}>
{children}
</a>
)
}
)
BackButton.displayName = 'BackButton'
export { BackButton }
Is this.props.history the browser's history? If so, you can do this.props.history.go(-1) to go back to the previous page.
As always with Gatsby, watch out when you use methods from browser, since they don't exist during html generation:
export default () => (
<button onClick={() => {
typeof history !== 'undefined' && history.go(-1)
}}>back</button>
)
For a function component in Gatsby:
<a onClick={() => window.history.back()}>Go back</a>
The gatsby navigate function is type as NavigateFn.
Which you can find declare as:
export interface NavigateFn {
(to: string, options?: NavigateOptions<{}>): Promise<void>;
(to: number): Promise<void>;
}
So, as you can see, you either can pass the route you want to redirect to, or an specific number.
Try with navigate(-1)
This should work
import { navigate } from "#gatsbyjs/reach-router";
<button onClick={() => navigate(-1)}>Back to previous page</button>
It goes to the previous page