How do I go to previous page in gatsby (history.goBack) - javascript

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

Related

React-Bootstrap Alert firing "onClose" immediately upon opening

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");
}}

How to pass an instance to a function within a component in reactjs

If the terms used in question are incorrect please bare with me as this is the first time i'm using react js. I have written some code by referring lot of blogs, youtube, docs etc. and now i'm stuck since it is a mix of everything.
I have a requirement where i make a get call to an endpoint (about.js component) which returns json data which will be passed to (workspace.js component) where it is rendered and displayed. so far it is working fine.
next step, there is a link 'delete'(in cards element of workspace.js) on clicking, it should make a post call to an endpoint with the project_name. here i'm unable to make it work (confused with const, functions etc).
below is the code : (about.js)
import React, { useState, useEffect } from "react";
import Card from "react-bootstrap/Card";
import "./About.css";
import axios from "axios";
import Account from "./Workspace";
function About() {
const [resp_data, setdata] = useState("");
useEffect(() => {
const axios = require("axios");
axios({
method: "get",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
url: "http://127.0.0.1:8000/api/projects/",
})
.then(function (response) {
setdata(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {});
}, []);
if (resp_data != "") {
return (
<div>
<Account user={resp_data} />
</div>
);
} else {
return <h2>Loading...</h2>;
}
}
export default About;
workspace.js
import React, { Component } from "react";
import Card from "react-bootstrap/Card";
const Account = (props) => {
function handleClick(event) {
alert(event);
//need to get the project_name here
//make post call to an endpoint with project_name as data
}
const users = props.user.data;
return (
<div>
{users.map((user) => (
<div className="card-rows">
<Card className="card" key={user.Id}>
<Card.Body>
<Card.Title>
<b>Project : </b>
{user.project_name}
</Card.Title>
<Card.Subtitle className="mb-2 text-muted">
<b>DataSet : </b>
{user.dataset_name}
</Card.Subtitle>
<Card.Subtitle className="mb-2 text-muted">
<b>DataType : </b>
{user.data_type}
</Card.Subtitle>
<Card.Link
href="#"
name="hello"
className="delete"
onClick={this.handleClick({user.project_name})} // call handleclick and the projectname should be available within the function
>
Delete
</Card.Link>
<Card.Link href="/launch" className="launch">
Launch
</Card.Link>
</Card.Body>
</Card>
</div>
))}
</div>
);
};
export default Account;
it would be a great assistance if anyone could help
If you are in an functional component, you can get the user prop by adding curl braces. Also modify your onClick.
React onClick Event Handling
I would recommend you to go through React Documentation thoroughly if starting out.
This should work for you.
const Account = ({user}) => {
//use curly braces around props to fetch user prop
function handleClick(project_name) {
alert(project_name);
//need to get the project_name here
//make post call to an endpoint with project_name as data
}
return(
... //above code
<Card.Link
href="#"
name="hello"
className="delete"
onClick={() => handleClick(user.project_name)}
>
Delete
</Card.Link>
... //below
)
I believe the issue is how you are handing the onClick function in the Card.Link component.
OnClick functions take a function to handle the event. So right now you are just invoking a function but that wouldnt have any effect on the event that is implicitly being passed into the component.
More can be found here: https://reactjs.org/docs/handling-events.html
<Card.Link
href="#"
name="hello"
className="delete"
onClick={() => this.handleClick({user.project_name})} />
The problem in your implementation lies here
onClick={this.handleClick({user.project_name})}
because this would make the call while component gets rendered. But the react synthetic event handlers expect a function reference to be passed.
In order to achieve the same You can simply convert the onClick handler for Delete button
from
onClick={this.handleClick({user.project_name})}
to
onClick={() => this.handleClick(user.project_name)}
That would look like below
<Card.Link
href="#"
name="hello"
className="delete"
onClick={() =>
this.handleClick(user.project_name)}>
Delete
</Card.Link>
So, directly the handleClick method would receive the project_name.
const handleClick = project_name => {
console.log(projectName);
//You can use `project_name ` for making the API call.
}

React render list only when data source changes

Basically I have a modal with a state in the parent component and I have a component that renders a list. When I open the modal, I dont want the list to re render every time because there can be hundreds of items in the list its too expensive. I only want the list to render when the dataSource prop changes.
I also want to try to avoid using useMemo if possible. Im thinking maybe move the modal to a different container, im not sure.
If someone can please help it would be much appreciated. Here is the link to sandbox: https://codesandbox.io/s/rerender-reactmemo-rz6ss?file=/src/App.js
Since you said you want to avoid React.memo, I think the best approach would be to move the <Modal /> component to another "module"
export default function App() {
return (
<>
<Another list={list} />
<List dataSource={list} />
</>
);
}
And inside <Another /> component you would have you <Modal />:
import React, { useState } from "react";
import { Modal } from "antd";
const Another = ({ list }) => {
const [showModal, setShowModal] = useState(false);
return (
<div>
<Modal
visible={showModal}
onCancel={() => setShowModal(false)}
onOk={() => {
list.push({ name: "drink" });
setShowModal(false);
}}
/>
<button onClick={() => setShowModal(true)}>Show Modal</button>
</div>
)
}
export default Another
Now the list don't rerender when you open the Modal
You can use React.memo, for more information about it please check reactmemo
const List = React.memo(({ dataSource, loading }) => {
console.log("render list");
return (
<div>
{dataSource.map((i) => {
return <div>{i.name}</div>;
})}
</div>
);
});
sandbox here

How to push to url in gatsby js?

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>

Delete button without { Component } in ReactJs

This is surely really easy but I didn't find the solution.. I want to use the delete button but I'm getting an error. Thanks in advance guys.
This is the code where props call the properties of a Toy class parent, I want to delete by Id using MongoDB:
import React, { useContext } from 'react';
import UserContext from '../../context/UserContext';
import Axios from 'axios';
export default function AdminOptions(props) {
const { userData } = useContext(UserContext);
console.log(props.value._id)
//I tried this log and it gives me the id of the toy
deleteToy = async(id) => {
await Axios.delete('api/toys/delete' + id);
alert('Toy deleted');
}
return (
<div>
{userData.user ? (
<>
<br/>
<button className="btn btn-danger" onClick={this.deleteToy(props.value._id)}>
Delete toy
</button>
</>
) : (
<>
</>
)}
</div>
)
}
And this is the error I get
Failed to compile.
Line 15:5: 'deleteToy' is not defined no-undef
You are using the variable deleteToy without defining it (with either const, let or var), hence the error.
You are referring to this.deleteToy, yet your variable is just deleteToy.
In your event handler, you are not passing a function reference but actually calling the function right away. You can prepend () => to fix it (passing an arrow function that then calls yours when called). (Thanks, Emre Koc, I missed that.)
The fixed code would look like this:
import React, { useContext } from 'react';
import UserContext from '../../context/UserContext';
import Axios from 'axios';
export default function AdminOptions(props) {
const { userData } = useContext(UserContext);
console.log(props.value._id)
//I tried this log and it gives me the id of the toy
const deleteToy = async(id) => {
await Axios.delete('api/toys/delete' + id);
alert('Toy deleted');
}
return (
<div>
{userData.user ? (
<>
<br/>
<button className="btn btn-danger" onClick={() => deleteToy(props.value._id)}>
Delete toy
</button>
</>
) : null}
</div>
)
}
Add const before deleteToy . It will work

Categories

Resources