Pushing data from one component to a another - javascript

So I am having a problem with payment Component. Basically I want when I press on the link it pushes (ClassG imageG and PriceG) into the Payment Component where I can style them again I have tried something but it is giving me the straight information(Arayys) when I click on the Link. That is not exactly what I want. I would like some help if possible. Thanks in Advance
import React from "react";
import data from "../data.json";
import { Link } from "react-router-dom";
function G() {
return (
<div className='bg-black '>
{data.filter(d =>
d.classG &&
d.imageG &&
d.priceG)
.map((postData) => {
return (
<div className='bg-black' key={postData.id} >
<div className='bg-black '>
<img
alt=""
className="w-full object-contain "
src={postData.imageG}
></img>
<h1 className=" ml-24 mlg:ml-6 mlg:mt-2 mlg:static text-5xl mlg:text-2xl text-blue-400
absolute top-48">
{postData.classG}
</h1>
<h1 className="text-lg mlg:mb-2 mlg:ml-6 mlg:mt-2 mlg:static font-bold text-green-800
font-mono ml-24 top-64 absolute" >
{postData.priceG}
</h1>
<Link
to={`/payment/${postData.id}`}
className="py-1 px-2 mlg:ml-6 mlg:mt-14 mlg:static text-black-600 h-8 ml-24 top-72 bg-
white w-32 text-center text-gray-red
rounded-full focus:outline-none focus:ring-2 focus:ring-gray-600 absolute"
>
Buy Now
</Link>
<div id='New' className="flex flex-col mt-40 justify-center border-white text-center items-
center bg-black" >
<h1 className='tracking-tighter mb-20 text-white text-base md:text-6xl'>What's new in
2021</h1>
<h1 className=' md:p-4 md:w-2/4 font-sans mb-16 text-white '>{postData.newG} </h1>
</div>
</div>
</div>
)
}
export default G
json file
[
{
"id":1,
"classG":"G-Class",
"imageG":"./ModImages/Gclass.jpg",
"priceG":"Starting at $154,900"
"newE": "some text"
},
]
Payment Component
import React from "react";
import data from "./Models/data.json";
function Payment(props) {
console.log(props);
const {
match: {
params: { dataId }
}
} = props;
const item = data.find(({ id }) => id === Number(dataId));
return (
<div className="ml-20">
<pre>{JSON.stringify(item, null, 2)}</pre>
</div>
);
}
export default Payment;
App Component
import React,{useState, useEffect} from 'react'
import './assets/main.css'
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
function App() {
return (
<div className='' >
<div>
<Router>
<Header />
<Switch>
<Route path="/a">
<A />
</Route>
<Route path="/payment/:dataId" component={Payment}>
</Route>
</Switch>
</Router>
</div>
</div>
);
}
export default App;

In order to send the specific product data you can use the route state of the routing transition.
Link - to: object
<Link
to={{
pathname: `/payment/${postData.id}`,
state: {
postData,
},
}}
className="..."
>
The route state can be accessed on the receiving route's component on the location object. Components rendered by a Route's render, component, or children prop receive all the route props.
function Payment(props) {
const {
location: {
state: {
postData, // <-- access route state from location.state
},
},
match: {
params: { dataId }
},
} = props;
const {
classG,
imageG,
priceG,
// ... any other postData object properties
} = postData;
return (
<div className="ml-20">
<pre>{JSON.stringify(postData, null, 2)}</pre>
</div>
);
}

Related

React Query Hook Not Running On Initial Load

Here is my React component. The hook I am trying to get to work is useGetNotesQuery.
On initial load of the component, it does not run. If I tab switch, or create a new note, then the hook will be called and the component will update. I don't have this problem with other hooks and I can't seem to figure out what I am doing wrong. I'm still pretty new to react-query. I've verified that when the hook is called on tab switch or the creation of a new note, the correct data is being passed in and the hook works as expected. It just will not run on initial load.
import React, { useState } from 'react';
import useGetNotesQuery from 'hooks/notes/useNotes';
import { useCreateNote } from 'hooks/notes/useCreateNote';
import Note from './Note';
export default function Notes({ projectItemId, itemId, itemType }: any) {
const createNote = useCreateNote();
const {
data: notes,
isLoading,
isError
} = useGetNotesQuery({ projectItemId, itemId, itemType });
const [body, setBody] = useState('');
const createNewNote = async () => {
await createNote.mutateAsync({
body,
projectItemId,
itemId,
itemType
});
setBody('');
};
return (
<section aria-labelledby="notes-title">
{!isLoading && (
<div className="sm:overflow-hidden sm:rounded-lg">
{console.log(notes)}
<div className="divide-y divide-gray-200">
<div className="px-4 py-5 sm:px-6">
<h2
id="notes-title"
className="text-lg font-medium text-gray-900"
>
Notes
</h2>
</div>
<div className="px-4 py-6 sm:px-6">
<ul role="list" className="space-y-8">
{notes?.map((note) => (
<Note key={note.id} note={note} />
))}
</ul>
</div>
</div>
<div className="bg-gray-50 px-4 py-6 sm:px-6">
<div className="flex space-x-3">
{/* <div className="flex-shrink-0">
<img
className="h-10 w-10 rounded-full"
src={user.imageUrl}
alt=""
/>
</div> */}
<div className="min-w-0 flex-1">
<form action="#">
<div>
<label htmlFor="comment" className="sr-only">
About
</label>
<textarea
id="comment"
name="comment"
rows={3}
className="block w-full p-2 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm text-black"
placeholder="Add a note"
value={body}
onChange={(e) => setBody(e.target.value)}
/>
</div>
<div className="mt-3">
<button
type="submit"
onClick={(e) => {
e.preventDefault();
createNewNote();
}}
className="inline-flex items-center justify-center rounded-md border border-transparent bg-blue-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
>
Comment
</button>
</div>
</form>
</div>
</div>
</div>
</div>
)}
</section>
);
}
Here is the hook
import { getNotesById } from './../../queries/notes/get-notes';
import { useQuery } from 'react-query';
function useGetNotesQuery({ projectItemId, itemId, itemType }: any) {
return useQuery('notes', async () => {
if (projectItemId) {
return getNotesById({ projectItemId, itemId, itemType }).then(
(result) => result.data
);
}
});
}
export default useGetNotesQuery;
My _app.tsx file in NextJS
import 'styles/main.css';
import 'styles/chrome-bug.css';
import '#/styles/tailwind.css';
import 'katex/dist/katex.css';
import '../styles/globals.css';
import 'react-datepicker/dist/react-datepicker.css';
import { useEffect, useState } from 'react';
import React from 'react';
import { SessionContextProvider } from '#supabase/auth-helpers-react';
import { createBrowserSupabaseClient } from '#supabase/auth-helpers-nextjs';
import { AppProps } from 'next/app';
import { MyUserContextProvider } from 'utils/useUser';
import type { Database } from 'types_db';
import { SidebarProvider } from 'context/SidebarContext';
import { QueryClient, QueryClientProvider } from 'react-query';
// import { ReactQueryDevtools } from 'react-query/devtools';
import { ThemeProvider } from 'next-themes';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 3
}
}
});
export default function MyApp({ Component, pageProps }: AppProps) {
const [initialContext, setInitialContext] = useState();
const [supabaseClient] = useState(() =>
createBrowserSupabaseClient<Database>()
);
useEffect(() => {
document.body.classList?.remove('loading');
}, []);
return (
<QueryClientProvider client={queryClient}>
<SessionContextProvider supabaseClient={supabaseClient}>
<MyUserContextProvider initial={initialContext}>
<SidebarProvider>
<ThemeProvider
attribute="class"
enableColorScheme={false}
defaultTheme="light"
>
<Component {...pageProps} />
</ThemeProvider>
{/* <ReactQueryDevtools initialIsOpen={false} /> */}
</SidebarProvider>
</MyUserContextProvider>
</SessionContextProvider>
</QueryClientProvider>
);
}
What do your other hooke return? Your query getNotesById is returning result.data, but the useQuery structure expects a parsed result object, like the example below:
const fetchUsers = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
return res.json();
};
const response = useQuery("users", fetchUsers);

How to pass icons as props in react with typescript

I am new to typescript and started a simple project. I have a sidebar component that is made up of several sidebarNavigationItem components. Each Sidebar item has an Icon and Title, as shown below.
Sidebar.tsx
import SidevarNavigationItem from "./SidevarNavigationItem"
import { HomeIcon } from "#heroicons/react/24/solid"
import { StarIcon } from "#heroicons/react/24/solid"
const Sidebar = () => {
return (
<nav
id="sidebar"
className="p-2 mt-5 max-w-2xl xl:min-w-fit sticky top-20 flex-grow-0.2 text-center h-screen"
>
<div id="navigation">
<SidevarNavigationItem Icon={<HomeIcon />} name="Homepage" source="/" />
<SidevarNavigationItem
Icon={<StarIcon />}
name="Tournaments"
source="/tournaments"
/>
</div>
</nav>
)
}
export default Sidebar
SidebarNavigationItem.tsx
import Link from "next/link"
import { FunctionComponent } from "react"
interface Props {
Icon: React.ElementType
name: string
source: string
}
const SidevarNavigationItem: FunctionComponent<Props> = ({
Icon,
name,
source,
}) => {
return (
<Link href={source}>
<div className="flex items-center cursor-pointer text-3xl space-x-5 justify-center">
{Icon && <Icon classname="h-8 w-8 text-red-500" />}
<p className="hidden sm:inline-flex font-medium">{name}</p>
</div>
</Link>
)
}
export default SidevarNavigationItem
The issue is that I can't style the icons that have been passed down as props when the type is JSX.Element. Changing the type of the Icon to React.ElementType will let me add styles but causes an error in the parent that says
Type 'Element' is not assignable to type 'ElementType'
What do I do?
You need to pass the component reference itself instead of its rendered jsx.
So, in your Sidebar.tsx component, you need to replace these lines:
Icon={<HomeIcon />}
Icon={<StarIcon />}
with these lines respectively:
Icon={HomeIcon}
Icon={StarIcon}
The final code should be like this:
<div id="navigation">
<SidevarNavigationItem Icon={HomeIcon} name="Homepage" source="/" />
<SidevarNavigationItem
Icon={StarIcon}
name="Tournaments"
source="/tournaments"
/>
</div>

Hydration error when fetching data from array of objects

I am using Nextjs and there is a sidebar in which I am trying to get random 5 posts from an array of objects. The defined function is working fine and displaying 5 posts but I am getting a Hydration error showing Prop alt did not match. When I tried to display it on the console the alt value is different.
import Link from 'next/link';
import Image from 'next/image';
import { BlogData } from '../data/blogdata';
function getMultipleRandom() {
const shuffled = [...BlogData].sort(() => 0.5 - Math.random());
return shuffled.slice(0, 5);
}
const Sidebar = () => {
return (
<>
<h2 className='font-roboto text-3xl font-semibold pb-10'>Featured Posts</h2>
{
getMultipleRandom().map((val) => {
return (
<div key={val._id} className='flex flex-col pt-5'>
<div className='w-56 pr-5'><Image src={val.featuredImage} alt={val.alt} width={1200} height={800} className=' rounded-3xl' /></div>
<Link href={`/blog/${val.slug}`}><a><h3 className='text-sm font-poppins font-medium hover:text-[#5836ed] transition-all duration-300'>{val.title}</h3></a></Link>
</div>
);
})
}
</>
)
}
export default Sidebar;
try this code :
import Link from "next/link";
import Image from "next/image";
import { BlogData } from "../data/blogdata";
import { useEffect, useState } from "react";
const Sidebar = () => {
const [shuffled, setShuffled] = useState([]);
const [loading, setLoading] = useState(true); // anyting you want !!!
useEffect(() => {
if (loading) {
const x = [...BlogData].sort(() => 0.5 - Math.random());
setShuffled(x.slice(0, 5));
setLoading(false);
}
}, [loading]);
return (
<>
<h2 className="font-roboto text-3xl font-semibold pb-10">
Featured Posts
</h2>
{loading ? <div>loading ... </div> : shuffled.map((val) => {
return (
<div key={val._id} className="flex flex-col pt-5">
<div className="w-56 pr-5">
<Image
src={val.featuredImage}
alt={val.alt}
width={1200}
height={800}
className=" rounded-3xl"
/>
</div>
<Link href={`/blog/${val.slug}`}>
<a>
<h3 className="text-sm font-poppins font-medium hover:text-[#5836ed] transition-all duration-300">
{val.title}
</h3>
</a>
</Link>
</div>
);
})}
</>
);
};
export default Sidebar;

Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider> while using useselector

1.header.js
import Image from "next/image";
import {
MenuIcon,
SearchIcon,
ShoppingCartIcon,
} from "#heroicons/react/outline";
import { signIn, signOut, useSession } from "next-auth/react";
import { useRouter } from "next/router";
import { useSelector } from "react-redux";
import { selectItems } from "../slices/basketSlice";
import { Provider } from "react-redux";
function Header() {
const { data: session } = useSession();
const router = useRouter();
const items= useSelector(selectItems);
return (
<header>
<div className="flex items-center bg-amazon_blue p-1 flex-grow py-2">
<div className="mt-2 flex items-center flex-grow sm:flex-grow-0">
<Image
onClick={() => router.push("/")}
src='https://links.papareact.com/f90'
width={150}
height={40}
objectFit="contain"
className="cursor-pointer"
/>
</div>
{/*search bar*/}
<div className="hidden sm:flex items-center h-10 rounded-md flex-grow cursor-pointer bg-yellow-400 hover:bg-yellow-500">
<input className="p-2 h-full w-6 flex-grow flex-shrink rounded-l-md focus:outline-none px-4" type="text" />
<SearchIcon className="h-12 p-4"/>
</div>
<div className="text-white flex items-center text-xs space-x-6 mx-6 whitespace-nowrap">
<div onClick={session ? signIn:signOut} className="link">
<p className="hover:underline">{session ? session.user.name:"signin"}</p>
<p className="font-extrabold md:text-sm">Acount & lists</p>
</div>
<div className=" link">
<p>Returns</p>
<p className="font-extrabold md:text-sm">& orders</p>
</div>
<div onClick={() => router.push("/checkout")} className=" link relative flex items-center">
<span className="absolute top-0 right-0 md:right-10 h-4 w-4 bg-yellow-400 rounded-full text-center text-black font-bold">
{items.length}
</span>
<ShoppingCartIcon className="h-10 "/>
<p className="hidden md:inline font-extrabold md:text-sm mt-2">Bascket</p>
</div>
</div>
</div>
{/*bottom nav*/}
<div className="flex items-center space-x-3 p-2 pl-6 bg-amazon_blue-light text-white text-sm">
<p className="link flex items-center ">
<MenuIcon className="h-6 mr-5"/>
all</p>
<p className="link">featured </p>
<p className="link">new arrival </p>
<p className="link">catalog </p>
<p className="link hidden lg-inline-flex">electronics </p>
</div>
</header>
);
}
export default Header;
bascketslice.js
'''
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
items: [],
};
export const basketSlice = createSlice({
name: "basket",
initialState,
reducers: {
addToBasket: (state, action) => {
state.items = [...state.items, action.payload]
},
removeFromBasket: (state, action) => {},
},
});
export const { addToBasket, removeFromBasket } = basketSlice.actions;
// Selectors - This is how we pull information from the Global store slice
export const selectItems = (state) => state.basket.items;
export default basketSlice.reducer;
'''
product.js
'''
import Image from "next/image";
import {useState} from "react";
import{ StarIcon} from"#heroicons/react/solid";
import Currency from "react-currency-format";
import { useDispatch } from "react-redux";
import {addToBasket} from "../slices/basketSlice";
const MAX_RATING =5;
const MIN_RATING =1;
function Product({id, title, price, description, category,image}) {
const dispatch = useDispatch();
const{rating}= useState(
Math.floor(Math.random() * (MAX_RATING - MIN_RATING +1)) + MIN_RATING
);
const addItemToBascket = () => {
const product = {id, title, price, description, category,image};
// sending the product as an action to bascket slice
dispatch(addToBasket(product))
};
return (
{category}
<Image src={image} height={200} width={200} objectFit="contain" />
<h4 className="flex">{title}</h4>
<div className="flex">
{Array(rating)
.fill()
.map((_, i)=>(
<StarIcon className="h-5 text-yellow-500"/>
))}
</div>
<p className="text-xs my-2 line-clamp-2">{description}</p>
<div className="mb-5">
<Currency quantity={price}/>
</div>
<button onClick={addItemToBascket} className=" mt-auto button">Add to Basket</button>
</div>
);
}
export default Product
'''
store.js
import { configureStore } from "#reduxjs/toolkit";
import basketReducer from "../slices/basketSlice";
export const store = configureStore({
reducer: {
basket: basketReducer,
},
});
_app.js
import { Provider } from 'react-redux'
import { store } from '../app/store'
import '../styles/globals.css'
import { SessionProvider } from "next-auth/react"
const MyApp = ({ Component, pageProps: {session,...pageProps} }) => {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
);
};
export default MyApp
how do i use provider in the code
my repository :- https://github.com/Shadow2389/nmz-2.git
It seems we're both fans of Sonny. Your problem there is that you need to wrap up your App.js in
<Provider>
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
</Provider>
But then you'll most likely have a "Hydration error", if so, just remove the "Math.floor(Math.random() * (MAX_RATING - MIN_RATING +1)) + MIN_RATING"
Apparently with the new updates we can no longer use the useState() hook as we used to, so you have 3 options:
1.- Remove the "Math.floor(Math.random() * (MAX_RATING - MIN_RATING +1)) + MIN_RATING"
2.- Set a fixed rating for all products
3.- Set a number for your API (which you cannot, since you are using FakeStoreAPI)
This is due to basic rules of Hooks, since a Random number is "umpredictable", but now I don't know why it has that problem (although you're setting a min and a max)

Unhandled Rejection (TypeError): setToken is not a function

I am having trouble with React while trying to set a token for user to log into the application. I followed the steps here to create a login process but it gives out the Unhandled Rejection (TypeError): setToken is not a function error and I am not able to correct it.
Here are the associated codes starting with from app.js
import React from 'react';
import { useState } from 'react';
import Login from './Pages/Login.js';
import Signup from './Pages/Signup';
import Dashboard from './Pages/Dashboard.js';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import useToken from './Pages/useToken'
function App() {
const { token, setToken } = useToken();
if (!token) {
return <Login setToken={setToken} />
};
return (
<div className="">
<BrowserRouter>
<Switch>
<Route exact path="/">
<Login />
</Route>
<Route exact path="/dashboard">
<Dashboard />
</Route>
<Route exact path="/signup">
<Signup />
</Route>
</Switch>
</BrowserRouter>
</div>
);
}
export default App;
Login.js
import React from 'react';
import { useState } from 'react';
import PropTypes from 'prop-types';
async function loginUser(credentials) {
return fetch('http://localhost:8080/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(credentials)
})
.then(data => data.json())
}
const Login = ({setToken}) => {
// username is email address
const [username, setUsername] = useState();
const [password, setPassword] = useState();
const handleSubmit = async(e) => {
e.preventDefault();
const token = await loginUser({
username,
password
});
setToken(token);
};
return (<>
<section>
<div className="flex items-center justify-center flex-col">
<div className="w-11/15 mt-24 rounded-lg flex flex-col items-center justify-center relative">
<span className="flex flex-col lg:flex-row">
<header className="text-5xl pr-4">Welcome to </header>
<header className="font-LoveloLine text-6xl font-bold text-center"> Mused</header>
</span>
</div>
</div>
</section>
<section>
<div className="flex items-center justify-center flex-col">
<div className=" lg:w-2/4 px-4 rounded-lg flex flex-col items-center justify-center relative" >
<div className="py-12">
<form action="" className="flex flex-col gap-2" onSubmit={handleSubmit}>
{/* Email address */}
<label htmlFor=""></label>
<input className="w-96 text-brand-Black bg-white border-brand-Blue rounded-lg py-3 focus:outline-none focus:ring-2 focus:ring-brand-Red focus:border-transparent" type="email" name="" placeholder="Email address" id="" onChange={(e) => { setUsername(e.target.value)}} />
<label htmlFor=""></label>
{/* Password */}
<input className="w-96 bg-white text-brand-Black border-brand-Blue rounded-lg py-3 focus:outline-none focus:ring-2 focus:ring-brand-Red focus:border-transparent" type="password" name="" placeholder="Password" id="" onChange={(e) => { setPassword(e.target.value)}} />
<div class="max-w-sm mx-auto py-4">
<label class="inline-flex items-center">
<input class="text-brand-Blue w-6 h-6 mr-2 focus:ring-indigo-400 focus:ring-opacity-25 border border-gray-300 rounded" type="checkbox" />
Remember me
</label>
</div>
{/* Login button */}
<div>
<button type="submit" className="bg-brand-Blue rounded-full w-full py-2 active:bg-brand-Blue-dark hover:bg-brand-Blue-dark">Login</button>
</div>
</form>
{/* Checkbox */}
{/* Signup button */}
<div className="flex flex-col items-center justify-center ">
<p className="py-6">or</p>
<button type="submit" className="bg-brand-Red rounded-full w-full py-2 active:bg-brand-Red-dark hover:bg-brand-Red-dark">Signup
</button>
</div>
</div>
</div>
</div>
</section>
</>
)
};
Login.propTypes = {
setToken: PropTypes.func.isRequired,
}
export default Login
Error is thrown for Login.js file "setToken(token)" function. It is not supposed to be a function
import { useState } from 'react';
const useToken = () => {
const getToken = () => {
const tokenString = localStorage.getItem("token");
const userToken = JSON.parse(tokenString);
return userToken?.token
};
const [token, setToken] = useState(getToken());
const saveToken = (userToken) => {
localStorage.setItem("token", JSON.stringify(userToken));
setToken(userToken.token);
}
return {
setToken: saveToken,
token
}
}
export default useToken
In my own case i discovered that I was passing the setToken function inside login route like this:
<Route path='/login setToken={setToken} />
instead of
<Route path='/login' exact element={<Login
setToken={setToken}
/>}
/>
You have to pass it to the component itself, not the route!
Your posting this as within only the component, as soon as you go to the route it disregards it. So from localhost:3000 it'll work fine, but because you've not passed it through the route setToken={token} it'll disregard it. Scratched my head at this for hours.

Categories

Resources