Hydrate Nextjs React Redux Thunk - javascript

Problem: Error: Hydration failed because the initial UI does not match what was rendered on the server.
How can I iterate the cart without having to create another state :c
const initialState = {
cart: Cookies.get("cart") ? JSON.parse(Cookies.get("cart")) : [],
loading: null,
error: null,
};
import Layout from "../../Layout";
import { connect } from "react-redux";
import { removeFromCart, clearCart } from "../../redux/actions/cart";
function PasarelaPago({ loading, removeFromCart, clearCart, cart }) {
return (
<Layout>
<div className="px-2 py-10">
<h1 className="text-2xl text-gray-600 font-bold tracking-wider text-center">
Pasarela de pago
</h1>
<div className="w-full lg:w-1/2 mx-auto">
<h3 className="text-lg font-light tracking-widest text-gray-500 px-4 my-4">
Tu bolsa de compras
</h3>
<div className="flex justify-between px-3 text-xs text-gray-400 border-b pb-2">
<div>PRODUCTOS</div>
<div>CANTIDAD</div>
<div>TOTAL</div>
</div>
<div className="flex flex-col gap-3">
ERROR!!
{cart && cart.map((item) => <div>{item.name}</div>)}
</div>
</div>
</div>
</Layout>
);
}
const mapStateToProps = (state) => ({
loading: state.Cart.loading,
cart: state.Cart.cart,
});
export default connect(mapStateToProps, {
removeFromCart,
clearCart,
})(PasarelaPago);

Related

Complexity in maping product , in shopping cart? Products array is not maping

it is the initial state of the redux toolkit, cartSlice and it is an object and products is an array having oneProduct as an object containing product information like image, price, description, etc.
This is cart slice
import { createSlice } from "#reduxjs/toolkit";
const cartSlice = createSlice({
name: "cart",
initialState: {
products: [],
quantity: 0,
total: 0,
},
reducers: {
addProduct: (state, action) => {
state.products.push(action.payload);
state.quantity += 1;
state.total += action.payload.price * action.payload.quantity;
},
removeProduct: (state, action) => {
let index = state.products.indexOf(action.payload)
state.quantity -= action.payload
state.products.splice(index, 1)
}
},
});
export const { addProduct ,removeProduct} = cartSlice.actions;
export default cartSlice.reducer;
THIS OBJECT IS initilaState of redux. In CONSOLE OF BROWSER
Object
products
:
Array(2)
0
:
{status: 'Specific products is here', oneProduct: {…}}
1
:
{status: 'Specific products is here', oneProduct: {…}}
length
:
2
[[Prototype]]
:
Array(0)
quantity
:
2
total
:
NaN
[[Prototype]]
:
Object
The problem is I am unable to map products array console above . Below is the code for the orders page and kindly Look at map Method
import React, { useState } from 'react'
import { Link } from 'react-router-dom';
import { useSelector } from 'react-redux';
const Order = () => {
const cart = useSelector((state) => state.cart)
console.log(cart)
const quantity = useSelector((state) => state.cart.quantity)
const [counter, setCounter] = useState(1);
const counterNumber = (type) => {
if (type === "inc") {
setCounter((prev) => prev + 1);
} else {
counter > 1 && setCounter((prev) => prev - 1);
}
};
return (
<>
<h1 className='font-bold text-xl text-center my-5'>CART PAGE</h1>
<div className='flex justify-around flex-wrap my-5 space-x-2'>
<div className='flex flex-col shadow-md p-2'>
{cart.products.oneProduct?.map((item)=>(
<div className="Product_info flex align-middle m-auto space-x-2 ">
<div className="product_image my-auto" key={item._id}>
<img src={item.img} alt="" className='w-16 h-16 ' />
</div>
<div className="details">
<h1 className='font-bold text-lg m-3'>{item.title}</h1>
</div>
<div className="price my-auto ">
<h1 className='font-bold text-2xl cursor-pointer'>$ {item.price}</h1>
</div>
<div className="ince_dec flex align-middle justify-center space-x-2 mr-5">
<div className="dec font-extrabold text-3xl my-auto" onClick={() => counterNumber("dec")}>-</div>
<h1 className='font-bold text-2xl my-auto'> {counter} </h1>
<div className="inc font-extrabold text-3xl my-auto cursor-pointer" onClick={() => counterNumber("inc")}>+</div>
</div>
<hr />
</div>
))}
</div>
<div className=" sideCart ml-1 text-white bg-blue-400 p-10 ">
<h1 className="text-center text-black font-extrabold">Product Quantity is: </h1>
<div className="text-white text-center font-bold my-2">{cart.products.length<1 ?"Cart is empty": quantity }</div>
<ul >
<div className="items flex align-middle items-center ">
</div>
</ul>
<div className="bton flex justify-center align-middle">
<Link to="/checkout">
<button className=" cart flex ml-4 text-white bg-black border-0 py-2 px-4 focus:outline-none lg:w-32 hover:bg-indigo-600 rounded md:w-4 md:px-6 text-sm">Checkout Now</button>
</Link>
</div>
</div>
</div>
</>
)
}
export default Order

Cannot read properties of undefined when in React component but works fine when in getStaticProps function

I'm trying to create a blog with Node.js, React and graphql. I'm new to all those technologies (including Java-/Typescript itself). I'd greatly appreciate your help.
Currently I'm stuck getting the data of my articles to show.
In the function getStaticProps I can read the data of my graphql response fine.
But when I pass that data as a parameter to the React component (as getStaticProps provides that data during build-time) I can't access that data anymore and get the error message "TypeError: Cannot read properties of undefined (reading 'articles')".
Below is my code:
import {GetStaticProps} from "next";
import {serverSideTranslations} from "next-i18next/serverSideTranslations";
import {ssrGetBlog} from "../../generated/page";
// #ts-ignore implicitly has any type
export default function Index(data) {
console.log(data.attributes) //TypeError: Cannot read properties of undefined (reading 'articles')
// below in getStaticProps this worked!?
return (
<div className="relative bg-gray-50 px-4 pt-16 pb-20 sm:px-6 lg:px-8 lg:pt-24 lg:pb-28">
<div className="absolute inset-0">
<div className="h-1/3 bg-white sm:h-2/3"/>
</div>
<div className="relative mx-auto max-w-7xl">
<div className="text-center">
<h2 className="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">
{data.blogHeading}
</h2>
<p className="mx-auto mt-3 max-w-2xl text-xl text-gray-500 sm:mt-4">
{data.blogDescription}
</p>
</div>
<div className="mx-auto mt-12 grid max-w-lg gap-5 lg:max-w-none lg:grid-cols-3">
{data.attributes.articles.data.map((article) => (
<div
key={article.attributes.title}
className="flex flex-col overflow-hidden rounded-lg shadow-lg"
>
<div className="flex-shrink-0">
<img
className="h-48 w-full object-cover"
src={article.attributes.articleImg.data.attributes.url}
alt=""
/>
</div>
<div className="flex flex-1 flex-col justify-between bg-white p-6">
<div className="flex-1">
<p className="text-sm font-medium text-indigo-600">
<a href={"not implemented: article.attributes.articleCategory.data.attributes.slug"} className="hover:underline">
{"none existent: article.attributes.articleCategory.data.attributes.categoryName"}
</a>
</p>
<a href={article.attributes.slug} className="mt-2 block">
<p className="text-xl font-semibold text-gray-900">
{article.attributes.title}
</p>
<p className="mt-3 text-base text-gray-500">
{article.attributes.shortDescription}
</p>
</a>
</div>
<div className="mt-6 flex items-center">
<div className="flex-shrink-0">
<a href={"not implemented: article.attributes.author.href"}>
<span className="sr-only">{"not implemented: article.author.authorName"}</span>
<img
className="h-10 w-10 rounded-full"
src={"not implemented: article.attributes.author.authorImg"}
alt=""
/>
</a>
</div>
<div className="ml-3">
<p className="text-sm font-medium text-gray-900">
<a href={"not implemented: article.attributes.author.authorUrl"} className="hover:underline">
{"not implemented: article.attributes.author.name"}
</a>
</p>
<div className="flex space-x-1 text-sm text-gray-500">
<time dateTime={article.attributes.publishedOn}>{article.attributes.publishedOn}</time>
<span aria-hidden="true">·</span>
<span>{"not implemented: article.attributes.readingTime"} read</span>
</div>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
const {locale} = context;
// #ts-ignore
const blogQuery = await ssrGetBlog.getServerPage({}, context);
const data = blogQuery.props.data?.blog?.data; //props.data?.blog?.data?.attributes;
//console.log(data); // works fine
//console.log(data.attributes.articles.data[0]); // works fine
return {
props: {
data,
...(await serverSideTranslations(locale || "", ["common"])),
},
};
};
Try this, maybe you're not accessing the component's props properly
export default function Index(props) {
console.log(props.data.attributes)
}
or
export default function Index({ data }) {
console.log(data.attributes)
}
export const getStaticProps: GetStaticProps = async (context) => {
const {locale} = context;
// #ts-ignore
const blogQuery = await ssrGetBlog.getServerPage({}, context);
const data = blogQuery.props.data?.blog?.data; //props.data?.blog?.data?.attributes;
//console.log(data); // works fine
//console.log(data.attributes.articles.data[0]); // works fine
const comething = await serverSideTranslations(locale || "", ["common"])
return {
props: {
data,
...comething,
},
};
};
Try this maybe?

How can I reduce quantity that are being received from backend and after reducing such quantity have to be set in backend?

import React from "react";
import { useParams } from "react-router-dom";
import Spinner from "../Spinner/Spinner";
import { useState } from "react";
import { useEffect } from "react";
const InventoryItemDetail = () => {
const [spinner, setSpinner] = useState(false);
const [itemDetail, setItemDetail] = useState({});
**const [newQuantity, setNewQuantity] = useState(itemDetail.quantity)**;
let { itemId } = useParams();
useEffect(() => {
setSpinner(true);
fetch(`http://localhost:5000/item/${itemId}`)
.then((res) => res.json())
.then((data) => setItemDetail(data));
setSpinner(false);
}, [itemId]);
if (spinner) {
return <Spinner />;
}
const handleRestock = (e) => {
e.preventDefault();
console.log(e.target.restock.value);
};
const handleDeleveredByOne = () => {
setNewQuantity(itemDetail.quantity - 1);
};
return (
<div className="bg-[#F0ECE3] lg:h-screen ">
<div className="w-11/12 mx-auto grid md:grid-cols-2 lg:grid-cols-3 justify-items-center items-center pt-32">
<div className="lg:w-[500px] ">
<img src={itemDetail.img} alt="" />
</div>
<div className="px-2 font-poppins mb-16 md:col-span-1 lg:col-span-2">
<div className="lg:w-3/6 border-2 border-red-500 mx-auto px-12 py-16">
<p className="text-xl py-2 font-bold">{itemDetail.name}</p>
<p className="">{itemDetail.shortDescripton}</p>
<p>
{" "}
Quantity: <span className="font-bold">{newQuantity}</span>
</p>
<p>
Price:{" "}
<span className="text-red-500 text-xl font-blod">
{" "}
${itemDetail.price}
</span>
</p>
<p className="font-light text-sm">
Supplier: {itemDetail.supplierName}
</p>
<button
onClick={handleDeleveredByOne}
className="mt-8 border-2 border-red-500 py-2 lg:px-6 w-full lg:w-fit hover:bg-red-500 hover:text-white"
>
Delivered
</button>
<form
onSubmit={handleRestock}
className="flex justify-end mt-8 lg:mt-0"
>
<div className="grid grid-cols-2 border-2 border-red-500 py-2 px-4 hover:bg-red-500 ">
<input
className="lg:w-20 text-lg order-2 outline-none "
type="number"
name="restock"
id=""
/>
<input
className="hover:text-white cursor-pointer"
type="submit"
value="Restock"
/>
</div>
</form>
</div>
</div>
</div>
</div>
);
};
export default InventoryItemDetail;
I want to display quantity that I have received from backend server and by clicking on delivered button, everytime it will reduce by one and save it to backend server. I have tried but it does not display quantity information and after clicking button it only works for first time.
How can I display quantity information and that I received from backend server and how to reduce it on every click and save it to backend server.

problem in sending or loading data to localstorage, when I do refresh- cart data is not there to show. I am loading data from firebase

I am loading data from firebase, so when I refresh, it takes time to load it. And added data are not present in the cart that,s why I am not getting any product in the cart. But I did follow the same process to store user data, and it,s working fine, which means I am getting a registered profile in console. Can anyone suggest me a solution for getting data in the cart?
sending data:
import { motion } from "framer-motion";
import React, { useEffect, useRef, useState } from "react";
import { MdShoppingBasket } from "react-icons/md";
import { actionType } from "../context/reducer";
import { useGlobalState } from "../context/stateProvider";
import NotFound from "../img/NotFound.svg";
const RowContainer = ({ flag, data, scrollValue }) => {
const [{ cartItems }, dispatch] = useGlobalState();
const [items, setItems] = useState([]);
const rowContainer = useRef();
const addToCart = () => {
dispatch({
type: actionType.SET_CARTITEMS,
cartItems: items,
});
localStorage.setItem("cartItems", JSON.stringify(items));
};
useEffect(() => {
addToCart();
}, [items]);
useEffect(() => {
rowContainer.current.scrollLeft += scrollValue;
}, [scrollValue]);
return (
<div
ref={rowContainer}
className={`w-full my-12 flex items-center ${
flag
? "overflow-x-scroll scrollbar-none scroll-smooth"
: "overflow-x-hidden flex-wrap justify-center"
}`}
>
{data && data.length > 0 ? (
data.map((item) => {
const { id, price, imageURL, calories, title } = item;
return (
<div
key={id}
className="w-350 min-w-[300px] md:min-w-[380px] md:my-10 backdrop-blur-lg mx-1 my-2 lg:mx-2 "
>
<div className="w-full flex flex-row items-center justify-between bg-white rounded-lg drop-shadow-lg py-2 px-4 hover:bg-whiteAlpha min-h-[150px]">
<motion.img
whileHover={{ scale: 1.2 }}
src={imageURL}
alt="img"
className="w-30 max-h-40 -mt-8 duration-100 drop-shadow-2xl"
/>
<div className="flex flex-col items-end justify-end gap-4">
<motion.div
whileTap={{ scale: 0.75 }}
className="w-8 h-8 rounded-md bg-orange-500 hover:bg-orange-600 "
onClick={() => setItems([...new Set(cartItems), item])}
>
<MdShoppingBasket className="text-white text-2xl m-1" />
</motion.div>
<div className=" w-full">
<p className="text-gray-800 md:text-lg text-base text-right">
{title}
</p>
<p className="text-sm text-gray-500 text-right">
<span className="text-orange-600">$</span> {price}
</p>
</div>
</div>
</div>
</div>
);
})
) : (
<div className="w-full flex flex-col items-center justify-center">
<img src={NotFound} className="h-340" alt="" />
<p className="text-center my-2 text-xl text-red-500">No data found</p>
</div>
)}
</div>
);
};
export default RowContainer;
fetching data
export const fetchCart = () => {
const cartInfo =
localStorage.getItem("cartItems") !== "undefined"
? JSON.parse(localStorage.getItem("cartItems"))
: localStorage.clear();
return cartInfo ? cartInfo : [];
};
You are clearing your data for no reason
localStorage.getItem("cartItems") !== "undefined"
should be
localStorage.getItem("cartItems") !== undefined

Why my redux state is go back to intial value on Page Refresh?

After SignIn, my authState becomes true, which is expected. and then It redirected to the home page. But after that If I refresh the page, my state goes back to initial value. what could be the reason of this?
Login Component:
import React, { useState, useEffect } from 'react';
import { toast } from 'react-toastify';
import axios from 'axios';
import { Redirect } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { setCurrentUser } from 'src/store/reducer/authReducer';
import jwtDecode from 'jwt-decode';
import { authenticate, isAuth } from '../helpers/auth';
import Protection from '../assets/Protection.svg';
import useInputState from '../hooks/useInputState';
const Login = (props) => {
const auth = useSelector((state) => state.auth);
const [submitted, setSubmitted] = useState(false);
const [btnText, setBtnText] = useState('Sign In');
const dispatch = useDispatch();
const { location } = props;
const initialValue = { name: '', email: '', password: '' };
const [state, onChangeHandler, reset] = useInputState(initialValue);
const { email, password } = state;
// submit data to backend
const handleSubmit = async (e) => {
e.preventDefault();
try {
const res = await axios.post(`${process.env.API_URL}/api/signin`, {
email,
password,
});
reset();
setSubmitted(true);
setBtnText('Submitted');
const { token: jwtToken } = res.data;
localStorage.setItem('jwtToken', jwtToken);
const decoded = jwtDecode(jwtToken);
dispatch(setCurrentUser(decoded));
} catch (err) {
const { errors } = err.response.data;
for (const error of errors) {
const msg = Object.values(error).toString();
toast.error(msg);
}
}
};
useEffect(() => {
if (location.message) {
toast.success(location.message);
}
}, [location.message]);
if (submitted && auth.isAuthenticated) {
return <Redirect to={{ pathname: '/', message: 'You are signed in' }} />;
}
return (
<div className="min-h-screen bg-gray-100 text-gray-900 flex justify-center">
<div className="max-w-screen-xl m-0 sm:m-20 bg-white shadow sm:rounded-lg flex justify-center flex-1">
<div className="lg:w-1/2 xl:w-5/12 p-6 sm:p-12">
<div className="mt-12 flex flex-col items-center">
<h1 className="text-2xl xl:text-3xl font-extrabold">
Sign In for MernAuth
</h1>
<form
className="w-full flex-1 mt-8 text-indigo-500"
onSubmit={handleSubmit}
>
<div className="mx-auto max-w-xs relative">
<input
className="w-full px-8 py-4 rounded-lg font-medium bg-gray-100 border-gray-200 placeholder-gray-500 text-sm focus:outline-none focus:border-gray-400 focus:bg-white mt-5"
type="email"
name="email"
placeholder="Email"
onChange={onChangeHandler}
value={email}
/>
<input
className="w-full px-8 py-4 rounded-lg font-medium bg-gray-100 border-gray-200 placeholder-gray-500 text-sm focus:outline-none focus:border-gray-400 focus:bg-white mt-5"
type="password"
name="password"
placeholder="Password"
onChange={onChangeHandler}
value={password}
/>
<button
className="mt-5 tracking-wide font-semibold bg-indigo-500 text-gray-100 w-full py-4 rounded-lg hover:bg-indigo-700 transition-all duration-300 ease-in-out flex items-center justify-center focus:shadow-outline focus:outline-none border-none outline-none"
type="submit"
>
<i className="fas fa-user-plus fa 1x w-6 -ml-2" />
<span className="ml-3">{btnText}</span>
</button>
</div>
<div className="my-12 border-b text-center">
<div className="leading-node px-2 inline-block text-sm text-gray-600 tracking-wide font-medium bg-white transform tranlate-y-1/2">
Or sign in with email or social login
</div>
</div>
<div className="flex flex-col items-center">
<a
className="w-full max-w-xs font-bold shadow-sm rounded-lg py-3
bg-indigo-100 text-gray-800 flex items-center justify-center transition-all duration-300 ease-in-out focus:outline-none hover:shadow focus:shadow-sm focus:shadow-outline mt-5"
href="/login"
target="_self"
>
<i className="fas fa-sign-in-alt fa 1x w-6 -ml-2 text-indigo-500" />
<span className="ml-4">Sign Up</span>
</a>
</div>
</form>
</div>
</div>
<div className="flex-1 bg-indigo-100 text-center hidden lg:flex">
<div
className="m-12 xl:m-16 w-full bg-contain bg-center bg-no-repeat"
style={{ backgroundImage: `url(${Protection})` }}
/>
</div>
</div>
</div>
);
};
export default Login;
my home component
import React, { useEffect } from 'react';
import { toast } from 'react-toastify';
const App = (props) => {
const { location } = props;
useEffect(() => {
if (location.message) {
toast.success(location.message);
}
}, [location.message]);
return <div>App</div>;
};
export default App;
I don't want the state to go back to its initial value on page refresh.
Your data is not persisted. Save the user token in the localStorage and when the app is initializing verify the localStorage and if there have value simply populate the store with this data.
Since you want to store user token, I would suggest that you use a cookie to store it, here is a link where you can find how to create and use a cookie.

Categories

Resources