This question already has answers here:
How to pass data from a page to another page using react router
(5 answers)
Closed 5 months ago.
I have 2 pages: (Datatable.jsx and Single.jsx).
I need to send id from Datatable.jsx to Single.jsx. After googling, i found that i can do that by using the <Link /> component, like this:
<Link
to={{
pathname: "/page",
state: data
}}
>
And then you can access the desired sent data to the second page:
render() {
const { state } = this.props.location
return (
// render logic here
)
}
I dont know how to apply this on my two pages:
Datatable.jsx:
//...
const Datatable = () => {
const [data, setData] = useState([]);
const handleDelete = (id) => {
setData(data.filter((item) => item.id !== id));
fetch(`https://api.factarni.tn/article/${id}`, {
method: "DELETE",
headers: {
Authorization:
"Bearer eyJhbGciOiJS...qw2QWltkyA",
},
}).then((response) => response.json());
};
useEffect(() => {
fetch("https://api.factarni.tn/article", {
method: "GET",
headers: {
Authorization:
"Bearer eyJhbGciOiJSUz...WltkyA",
},
})
.then((response) => response.json())
.then((json) => setData(json));
}, []);
const actionColumn = [
{
field: "action",
headerName: "Action",
width: 200,
renderCell: (params) => {
return (
<div className="cellAction">
<Link to="/users/test" style={{ textDecoration: "none" }}>
<div className="viewButton">Modifier</div>
</Link>
<div
className="deleteButton"
onClick={() => handleDelete(params.row.id)}
>
Delete
</div>
</div>
);
},
},
];
return (
<div className="datatable">
<div className="datatableTitle">
Add New Article
<Link to="/users/new" className="link">
<AddBusinessIcon className="icon" /> Add Article
</Link>
</div>
<DataGrid
className="dataGrid"
rows={data}
columns={userColumns.concat(actionColumn)}
pageSize={9}
rowsPerPageOptions={[9]}
checkboxSelection
/>
</div>
);
};
export default Datatable;
Single.jsx:
//...
const Single = ({ inputs, title }) => {
const [data, setData] = useState({
code: "",
article: "",
price: 0,
vat: 0,
status: 0,
company_id: 0,
});
const normalize = (v) => ({
code: v.code,
article: v.article,
price: Number(v.price),
vat: Number(v.vat),
status: Number(v.status),
company_id: Number(v.company_id),
});
function handle(e) {
const newdata = { ...data };
newdata[e.target.id] = e.target.value;
setData(newdata);
console.log(newdata);
}
const handleClick = async (e) => {
e.preventDefault();
const body = normalize(data);
await fetch("https://api.factarni.tn/article/create", {
method: "PUT",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
Authorization:
"Bearer eyJhbGciOiJ...w2QWltkyA",
},
});
};
return (
<div className="New">
<Sidebar />
<div className="newContainer">
<Navbar />
<div className="top">
<h1>{title}</h1>
</div>
<div className="bottom">
<div className="right">
<form>
<div className="formInput"></div>
{inputs.map((input) => (
<div className="formInput" key={input.id}>
<label>{input.label} </label>
<input
type={input.type}
placeholder={input.placeholder}
onChange={(e) => handle(e)}
id={input.label}
name={input.label}
value={input.label}
/>
</div>
))}
<button onClick={handleClick}>Update</button>
</form>
</div>
</div>
</div>
</div>
);
};
export default Single;
In the Database.jsx:
// ... code
<Link to={{ pathname: "/users/test", state: { id: params.row.id }}} style={{ textDecoration: "none" }}>
<div className="viewButton">Modifier</div>
</Link>
// ... code
In the Single.jsx:
import { useLocation } from 'react-router-dom';
// ... later in render function
const { state } = useLocation() // state.id should have your id
Although #deaponn's answer is good, you can also use the useNavigate hook and pass the id, name or any data in the state like below, using programmatic approach rather than Link component exported from react-router library
import { useNavigate } from "react-router-dom";
const navigate = useNavigate();
navigate('/(url on which you want to navigate)', { state: { id:1,name:encryptedId} });
On the navigated component, if you want to retrieve the passed id or name, you can use the useLocation hook as below:
import { useLocation } from "react-router-dom";
const location = useLocation();
var ttid = location.state.id;
Related
I've the following question, how can I display the data in react-native with useparams? I've the following code snippet in my Details.jsx
import React from 'react'
import {useParams} from 'react-router-dom'
const Details = () => {
const userData = JSON.parse(localStorage.getItem('user'))
const token = userData ? userData.accessToken : null
const params = useParams()
const [load, setLoad] = React.useState(false)
const getAccountDetails = React.useCallback(async () => {
setLoad(true)
await fetch (`http://localhost:4000/api/account/findonecard/${params.idCard}`, {
headers: {
'Authorization': `Bearer ${token}`
}
}).then(res => res.json()).then(response=>{
console.log(response)
//My response drops the data I need
})
}, [])
React.useEffect(() => {
getAccountDetails()
}, [getAccountDetails])
return (
<>
<div>Details</div>
{
!load ?
(
<Detail card={{
username: card.fullname,
description: card.description,
mainPic: card.pic_profile,
userTags: card.usertags
}} />
)
:
(
<div style={{ position: 'relative', zIndex: 99, color: '#000000', fontFamily: 'sans-serif', textAlign: 'center', margin: '60px auto' }}>No Card to show</div>
)
}
</>
)
}
export default Details
This releases an object with my data, such as photo, description, name, etc.
Although I tried to loop through the object, I can't display the data on my Front, what am I missing?
This is my Detail.jsx
const Detail = ({ card }) => {
return (
<div className="content">
<div className="content_card-container">
<ShowMore/>
<h2 className="content_card-username">{card.username}</h2>
<div
className="content_card-image"
style={{
backgroundImage:
`url(${card.cardImg})`
}}
/>
<div className="content_tags-slider">
<SliderComponent tags={card.userTags} />
</div>
</div>
<div className="content_user-description">
<p className="content_user-description-text">{card.description}</p>
</div>
<div className="content_choice-container">
<img src={Dislike} alt="" className="content_choice-icon" />
<img src={Like} alt="" className="content_choice-icon" />
</div>
</div>
);
};
To keep track of the account details we'll create a state.
const [accountDetails, setAccountDetails] = useState({});
In the getAccountDetails function you can set the state with the received data from the api. You're also mix 'n matching await and then, you should use one. Lets go with await for this one
const getAccountDetails = React.useCallback(async () => {
setLoad(true);
const response = await fetch(
`http://localhost:4000/api/account/findonecard/${params.idCard}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const data = await response.json();
// console.log(data);
setAccountDetails(data);
setLoad(false); // set load to false
}, []);
When passing the card data down to the Detail component we can use the accountDetails like so
<Detail
card={{
username: accountDetails.fullname,
description: accountDetails.description,
mainPic: accountDetails.pic_profile,
userTags: accountDetails.usertags,
}}
/>
You maybe want to set the initital state of load to true
I'm trying to make a redirection with every object from the SWAPI.
I already have URLs for my localhost (localhost:3000/people/1 for Luke), however, the only thing I can use for a unique ID is the url of each object ("https://swapi.dev/api/people/1/" for Luke)
I want to redirect to the localhost URL. But I don't see how I could.
Here is the code where I want to make that redirection :
// search_people.js
import React from "react";
import axios from "axios";
import "../App.css";
import { Card, ListGroup, ListGroupItem } from "react-bootstrap";
class SearchPeople extends React.Component {
state = {
name: "",
height: "",
mass: "",
hair_color: "",
skin_color: "",
eye_color: "",
birth_year: "",
gender: "",
url: "",
posts: [],
search: ""
};
componentDidMount = () => {
this.getPeople();
};
handleChange = ({ target }) => {
const { name, value } = target;
this.setState({
[name]: value,
});
};
getPeople = () => {
axios
.get("http://localhost:8080/api/people")
.then((response) => {
const data = response.data;
this.setState({ posts: data });
})
.catch(() => {
alert("error");
});
};
displayPeople = (posts) => {
const dataSearch = this.state.search.toLowerCase();
if (!posts.length) return null;
return posts
.filter((postTag) => postTag.name.toLowerCase().includes(dataSearch))
.map((post, index) => (
<div key={index}>
<div
>
<Card style={{ width: '24rem', left: "33%", margin: "2%" }} className>
<Card.Body>
<Card.Title>{post.name}</Card.Title>
</Card.Body>
<ListGroup className="list-group-flush">
<ListGroupItem>Height : {post.height}</ListGroupItem>
<ListGroupItem>Mass : {post.mass}</ListGroupItem>
<ListGroupItem>Hair color : {post.hair_color}</ListGroupItem>
<ListGroupItem>Skin color : {post.skin_color}</ListGroupItem>
<ListGroupItem>Eye color : {post.eye_color}</ListGroupItem>
<ListGroupItem>Birth year : {post.birth_year}</ListGroupItem>
<ListGroupItem>Gender : {post.gender}</ListGroupItem>
<ListGroupItem>URL : {post.url}</ListGroupItem>
// I want to make a clickable link to the localhost url here
</ListGroup>
</Card>
</div>
</div>
));
};
render() {
return (
<section className="container-md">
<h1>SWAPI People</h1>
<div>
<div className="input-group mb-3">
<input
className="form-control"
type="text"
name="search"
placeholder="Search by name"
value={this.state.search}
onChange={this.handleChange}
/>
</div>
</div>
<div>
{this.displayPeople(this.state.posts)}
</div>
</section>
);
}
}
export default SearchPeople;
What I tried is to slice the post.url and add the beginning of the localhost URL, but I couldn't find a place where to do that, because it will cause errors.
Is there any way to use that url value and transform that in my localhost value ?
I don't know why I can log value and i saw it have value, but when I set this value to ReactNode, it don't show anything. I just follow the docs of Nextjs.
What is my problem and how can I fix it?
my file name is [productId].tsx
My code
const productDetail : NextPage<Product>= (product) => {
console.log(product)
return (
<div>
<Navbar />
<div style={{ marginTop: 200 }}>
<div className="grid wide">
<div className="row">
<div className="col l-12 c-12 m-12">
<h1 className={styles.productName}>Name:{product.productName}</h1>
</div>
</div>
...
</div>
</div>
<Footer />
</div>
);
};
export const getStaticPaths: GetStaticPaths = async () => {
const { data } = await client.query<GetProductsQuery>({
query: GetProductsDocument,
variables: {
paginationOptions:{
skip:0
}
},
});
return {
paths: data.getProducts.products!.map((product) => ({
params: { productId: `${product.id}` },
})),
fallback: "blocking",
};
};
export const getStaticProps: GetStaticProps<
{ [key: string]: any },
{ productId: string }
> = async ({ params }) => {
const data = await client.query<GetProductQuery>({
query: GetProductDocument,
variables: { productId: params?.productId },
});
return {
props:{
product:data.data.getProduct.product
}
};
};
export default productDetail;
Have a nice day!
I don't know why but i fix my error by create a Props interface
interface Props{
product:Product
}
const productDetail: NextPage<Props> = ({product}) => {
...
}
i'm developing an ecommerce whit Nextjs and payments with Paypal.
This is my product component
const Product = () => {
const router = useRouter();
const { id, category } = router.query;
const [product, setProduct] = useState();
const [amount, setAmount] = useState(1);
useEffect(() => {
if (category) {
const foundProduct = products[category].find(
(element) => element.id == id
);
setProduct({ ...foundProduct, amount, total: foundProduct.price * amount });
}
}, [id, amount]);
return (
<>
{!product ? (
<Spinner />
) : (
<div className="product-wrapper">
<div className="product-image">
<Image src={product.image} />
</div>
<div className="product-info">
<h3>{product.title}</h3>
<p className="product-price">
{product.currency} {product.price}
</p>
<p className="product-description">
{product.description}
</p>
<div className="product-cart-container">
<div className="product-cart-handle">
<p onClick={() => amount > 1 && setAmount(amount - 1)}>-</p>
<span>{amount}</span>
<p onClick={() => setAmount(amount + 1)}>+</p>
</div>
<BuyButtton item={product} amount={amount} />
</div>
<div className="product-general">
<p>General information</p>
</div>
</div>
</div>
)}
</>
);
};
and this is my BuyButton component
const BuyButtton = ({ item }) => {
useEffect(() => {
console.log(item);
}, [item]);
return (
<div>
<PayPalScriptProvider
options={{
"client-id":"",
}}
>
<PayPalButtons
createOrder={async () => {
try {
const res = await axios({
url: "http://localhost:3000/api/payment",
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
data: JSON.stringify(item),
});
return res.data.id;
} catch (error) {
console.log(error);
}
}}
onApprove={(data, actions) => {
console.log(data);
actions.order.capture();
}}
style={{ layout: "horizontal", color: "blue" }}
/>
</PayPalScriptProvider>
</div>
);
};
So when i pass this props item to my BuyButton component works fine, the amount and total value updates correctly, the problem is when i do the axios call, it looks like the component stores the initial value of the item prop, so amount and value never changes, its always amount:1, value:item.value. Any ideas? Thanks
I tried storing the item prop in a state but it didin't work as i expected
The solution that solved my problem was adding forceReRender prop to PayPalButtons like this forceReRender={[item]}, so it re-render the button and gets the new amount value
In the Product component, you are passing item & amount to BuyButton
<BuyButtton item={product} amount={amount} />.
You need to add the amount to the BuyButton component as well.
const BuyButtton = ({ item, amount }) => {
and pass the amount in the request body in the axios call
data: JSON.stringify(item),
// need to add the amount data
There are numerous questions relating to useEffect() and running on initial page render. I am experiencing the same problem even after making sure my code is correct regarding parameters passed to useEffect.
useEffect(() => {
const token = Cookies.get('token');
setRole(Cookies.get('role'));
fetch(`${process.env.API_URL}/user/user-details`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"user_id": role,
"language": "en",
"api_token": token
})
})
.then((user) => user.json())
.then((thisUserData) => {
if (thisUserData.status_code == 200) {
setThisUser(thisUserData)
}
})
}, [])
For some reason this doesn't seem to be called after the component mounts.
Here is the full page code:
import Header from "../../../components/header"
import { useRouter } from "next/router"
import Link from 'next/link'
import Pagination from "../../../components/datatable/pagination"
import Cookies from "js-cookie"
import { parseCookies } from "nookies"
import { useState, useEffect } from "react"
import { Modal, Button } from "react-bootstrap";
import UserSidebar from "../../../components/user_sidebar"
import TabButtonUser from "../../../components/tabbuttonuser"
import Address from "../../../components/address"
const AdminUsers = ({ data }) => {
const router = useRouter()
// const limit = 3
// const lastPage = Math.ceil(totalPage / limit)
// console.log(data)
// console.log(listUsers)
/**
* Manage states
*/
const [show, setShow] = useState(false);
const [isEdit, setIsEdit] = useState(false);
const [fullNname, setFullName] = useState("");
const [emailID, setEmailID] = useState("");
const [country_code, setCountry_code] = useState("");
const [phone_number, setPhone_number] = useState("");
const [company_access, setCompany_access] = useState("");
const [isActive, setActive] = useState("");
const [userID, setUserId] = useState("");
const [role, setRole] = useState("");
const [thisUserData, setThisUser] = useState({})
useEffect(() => {
const token = Cookies.get('token');
setRole(Cookies.get('role'));
fetch(`${process.env.API_URL}/user/user-details`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"user_id": role,
"language": "en",
"api_token": token
})
})
.then((user) => user.json())
.then((thisUserData) => {
if (thisUserData.status_code == 200) {
setThisUser(thisUserData)
}
})
}, [])
/**
* Clear values
*/
const handleClose = () => {
setShow(false)
setIsEdit(false);
setUserId("")
setFullName("");
setEmailID("");
setCountry_code("");
setPhone_number("");
};
const handleShow = () => setShow(true);
/**
* Add User
* #param {*} e
* #returns
*/
const addUser = async (e) => {
e.preventDefault();
const token = Cookies.get('token');
if (!token) {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
const resUser = await fetch(`${process.env.API_URL}/user/create-sub-admin`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"full_name": fullNname,
"email_id": emailID,
"country_code": "+1",
"phone_number": phone_number,
"api_token": token
})
})
const res2User = await resUser.json();
console.log(res2User);
if (res2User.status_code == 200) {
handleClose();
setFullName("");
setEmailID("");
setCountry_code("");
setPhone_number("");
}
}
/**
* Get user details basis of user id for edit purpose
* #param {*} id
* #returns
*/
const getUser = async (id) => {
// e.preventDefault();
setIsEdit(true);
setShow(true);
setUserId(id)
const token = Cookies.get('token');
if (!token) {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
const userData = await fetch(`${process.env.API_URL}/user/user-details`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"user_id": id,
"language": "en",
"api_token": token
})
})
const userData2 = await userData.json();
console.log(userData2);
if (userData2.status_code == 200) {
// handleClose();
setFullName(userData2?.data?.full_name);
setEmailID(userData2?.data?.email_id);
setCountry_code(userData2?.data?.phone_number?.country_code);
setPhone_number(userData2?.data?.phone_number?.phone_number);
}
}
/**
* Remove user
* Api is pending
* #param {*} id
*/
const removeUser = async (id) => {
}
/**
*Update User
*
* #return {*}
*/
const updateUser = async () => {
// e.preventDefault();
const token = Cookies.get('token');
if (!token) {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
const resUser = await fetch(`${process.env.API_URL}/user/update-user`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"user_id": userID,
"full_name": fullNname,
"email_id": emailID,
"country_code": "+1",
"phone_number": phone_number,
"api_token": token,
"is_active": isActive
})
})
const res2User = await resUser.json();
console.log(res2User);
if (res2User.status_code == 200) {
setFullName("");
setEmailID("");
setCountry_code("");
setPhone_number("");
setIsEdit(false);
setShow(false);
setUserId("")
}
}
const address = {
"address_line": "",
"city_name": "",
"state_name": "",
"zip_code": ""
}
return (
<>
<Header />
<div className="container">
<div className="row">
<div className="col-3">
<UserSidebar data={thisUserData} />
</div>
<div className="col">
<div className="sidebarwrap">
{/* <TabButtonUser id={data?._id} /> */}
<h3 className="acc_title">My Company</h3>
<h2 className="login_name">Alliance Credit</h2>
<div className="acc_email">
email#company.com
</div>
<div className="acc_phone">+1234567890</div>
<Address address={address} />
<div className="ac_left acc_title">All Team Members</div>
<div className="ac_right">
{role.indexOf('admin') > -1 ?
<button className="btn btnedit" onClick={handleShow}>Add Sub-Admin</button>
: ''}
</div>
<div className="clearfix"></div>
<div className="listing">
<table id="example" className="table table-striped">
<thead>
<tr>
<th><div>Sr. Number</div></th>
<th><div>User Name</div></th>
<th><div>Date Added</div></th>
<th><div>Email</div></th>
<th><div>Actions</div></th>
</tr>
</thead>
<tbody>
{data?.map((item, index) => (
<tr key={index}>
<td>{index + 1}</td>
<td>{item.full_name}</td>
<td>{item.date_added}</td>
<td>{item.email_id}</td>
<td>
<>
<button className="btn viewmore" onClick={() => getUser(item._id)}>Edit User</button>
</>
</td>
</tr>
))}
</tbody>
</table>
{/* <Pagination page={page} totalPage={totalPage} lastPage={lastPage} /> */}
</div>
</div>
</div>
</div>
</div>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>{isEdit == false
? "Add Sub-Admin"
: "Edit Sub-Admin"
}</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className="popupform">
<form method="POST">
<div className="row">
<div className="col">
<label htmlFor="fullname" className="form-label">Full Name</label>
<input className="form-control" name="fullname" type="text" id="fullname" value={fullNname} onChange={(e) => setFullName(e.target.value)} />
</div>
</div>
<div className="row">
<div className="col">
<label htmlFor="emailID" className="form-label">Email</label>
<input className="form-control" name="emailID" type="text" id="emailID" value={emailID} onChange={(e) => setEmailID(e.target.value)} />
</div>
</div>
<div className="row">
<div className="col">
<label htmlFor="phone_number" className="form-label">Phone Number</label>
<input className="form-control" name="phone_number" type="text" id="phone_number" value={phone_number} onChange={(e) => setPhone_number(e.target.value)} />
</div>
</div>
<div className="row">
<div className="col">
{isEdit ? (
<>
<label htmlFor="phone_number" className="form-label">Active status</label>
<select className="form-control form-select" onChange={(e) => setActive(e.target.value)}>
<option value="0">Active</option>
<option value="1">Deactivate</option>
</select>
</>
) : ''
}
</div>
</div>
<div>
<input className="form-control" name="userID" type="hidden" id="company_logo_en" value={userID} />
</div>
</form>
</div>
</Modal.Body>
<Modal.Footer>
{isEdit == false
? <>
<Button variant="secondary" className="btn btnedit" onClick={handleClose}>Cancel</Button>
<Button variant="primary" onClick={addUser}>Add User</Button>
</>
:
<>
<Button variant="primary" className="btn btnremove" onClick={removeUser}>Remove User</Button>
<Button variant="primary" className="btn btnedit">Reset User</Button>
<Button variant="primary" onClick={updateUser}>Save</Button>
</>
}
</Modal.Footer>
</Modal>
</>
)
}
/**
*
*
* #export
* #param {*} { query: { page = 1, data = null, totalPage = 10 } }
* #return {*}
*/
// export async function getServerSideProps({ query: { page = 1, data = null, totalPage = 10 } }) {
export async function getServerSideProps(ctx) {
// const start = +page === 1 ? 0 : (+page + 1)
// const { locale, locales, defaultLocale, asPath } = useRouter();
const { token } = parseCookies(ctx)
if (!token) {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
const res = await fetch(`${process.env.API_URL}/user/list-sub-admin`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"language": 'en',
"api_token": token,
})
})
const data = await res.json()
/**
* limit, start, search item
*/
return {
props: {
data: data?.data || [],
}
}
}
export default AdminUsers
I am sure it is something simple that I've missed (it usually is) but I can't seem to spot it.
Thanks.
It's not clear for me this problem, but I try to write what I see: you have defined useEffect with the fetch without deps. In that fetch you use role state which is initialized to empty string in the first time. You set the role using setRole in the same useEffect but this has no effect for the precedent reasons.
My suggestion is to remove role state and redefine useEffect like this:
useEffect(() => {
const token = Cookies.get('token');
const role = Cookies.get('role');
fetch(`${process.env.API_URL}/user/user-details`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
user_id: role,
language: 'en',
api_token: token,
}),
})
.then((user) => user.json())
.then((thisUserData) => {
if (thisUserData.status_code == 200) {
setThisUser(thisUserData);
}
});
}, []);
React's state setters are asynchronous(see here), so when you use 'role' right after 'setRole', role is still an empty string. Thus the fetch returns nothing.
The answer may not be directly related to the question itself, but it may be useful to an another developer who is searching for an answer.
In my case I had two components and change rendering them when a button was clicked on the interface and I had accidentally put [] in dependencies, I fixed it by removing it.
Before,
useEffect(() => {
// your function
},[]);
After
useEffect(() => {
// your function
});