Why am I getting this error after parsing the cookie value? - javascript

I'm successfully setting the cookie and when I do console.log(getCookie('key')) I see this:
[{"pic":"https://something.jpg","des":"something","price":"something","score":"something","id":0,"explink":"something"}]
But when I run JSON.parse(getCookie('key')) I get this error:
SyntaxError: Unexpected token u in JSON at position 0
I was trying to use this:
import Layout from '../components/layout';
import { useState, createContext, useEffect } from 'react';
import AppContext from '../components/AppContext';
import '../styles/globals.css';
import { getCookies, getCookie, setCookie, deleteCookie } from 'cookies-next';
export default function MyApp({ Component, pageProps }) {
const [count, setcount] = useState(0);
const [card, setcard] = useState([]);
setCookie('key', JSON.stringify(card));
setcard(JSON.parse(getCookie('key')));
return (
<div>
<AppContext.Provider
value={{
count,
setcount,
card,
setcard,
}}
>
<Layout>
<Component {...pageProps} />
</Layout>
</AppContext.Provider>
</div>
);
}
Why am I getting this error?
I also tried setcard(getCookie('key')); but I got this error:
Error: Too many re-renders. React limits the number of renders to
prevent an infinite loop.
This error happened while generating the page. Any console logs will
be displayed in the terminal window.

getCookie('key') already parsed. So, you got this error. Try this:
setcard(getCookie('key'))
Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
I think you need to setcard inside useEffect hook.
useEffect(() => {
setcard(getCookie('key'))
}, [])

Related

ProductDetails.js:27 Uncaught TypeError: Cannot read properties of undefined (reading 'params')

The tutorial that I'm going off of is outdated I'm sure. I ran into this error ProductDetails.js:27
Uncaught TypeError: Cannot read properties of undefined (reading 'params')
This is my code for that line ProductDetails.js:27 is the dispatch, alert, error, match.params.id:
import React, { Fragment, useEffect } from 'react'
import { Carousel } from 'react-bootstrap'
import Loader from '../layout/Loader'
import MetaData from '../layout/MetaData'
import { useAlert } from 'react-alert'
import { useDispatch, useSelector } from 'react-redux'
import { getProductDetails, clearErrors } from '../../actions/productActions'
const ProductDetails = ({ match }) => {
const dispatch = useDispatch();
const alert = useAlert();
const { loading, error, product } = useSelector(state => state.productDetails)
useEffect(() => {
dispatch(getProductDetails(match.params.id))
if(error) {
alert.error(error);
dispatch(clearErrors())
}
}, [dispatch, alert, error, match.params.id])
export default ProductDetails
Not sure how much of the ProductDetails.js code but here it is, I left out my return function since it said my post was mostly code. Also posted below is my App.js code:
import { BrowserRouter as Router, Route, Routes } from "react-router-dom"
import Header from './components/layout/Header'
import Footer from './components/layout/Footer'
import Home from './components/Home'
import ProductDetails from './components/product/ProductDetails'
function App() {
return (
<Router>
<div className="App">
<Header />
<div className="container container-fluid">
<Routes>
<Route path="/" element={<Home /> } exact />
<Route path="/product/:id" element={<ProductDetails /> } exact />
</Routes>
</div>
<Footer />
</div>
</Router>
);
}
export default App;
For what it's worth the useParams hook hasn't changed since its introduction in react-router-dom#5 when React introduced hooks.
The issue is that match is simply undefined and/or not explicitly passed as a prop to this ProductDetails component. If you are using const params = useParams() and params as dependency then this very well likely is the cause of render looping as params will be a new object reference each render cycle. You should instead reference the id param directly.
I suggest also splitting up the effects into two separate effects so getProductDetails isn't dispatched because error updated, and vice-versa.
Example:
const ProductDetails = () => {
const dispatch = useDispatch();
const alert = useAlert();
const { id } = useParams();
const { loading, error, product } = useSelector(state => state.productDetails);
useEffect(() => {
if (id) {
dispatch(getProductDetails(id));
}
}, [dispatch, id]);
useEffect(() => {
if (error) {
alert.error(error);
dispatch(clearErrors());
}
}, [dispatch, alert, error]);
...

verify react functional component to be there

I'm new to react unit testing, here I have react code which works fine but need to unit test it.
I want to verify the component to be there, I have tried in two different ways and both of them does not work:
I'm using useSelector and useDispatch thats why connect(null,null).
my code:
M2SelectionCard.js:
function ConnectedSelectionCard({ classes }) {
return (
<Card data-testid="M2SelectionCardd" className={classes.selectionCard}>
<CardContent>
</CardContent>
</Card>
);
}
const M2SelectionCard = connect(null, null)(ConnectedSelectionCard);
export default M2SelectionCard;
first I did like this:
import React from "react";
import { expect } from "#jest/globals";
import { render, screen, cleanup } from "#testing-library/react";
import M2SelectionCard from "../M2SelectionCard";
test("test", () => {
render(<M2SelectionCard />);
const SelectionCardElement = screen.getByTestId("M2SelectionCardd");
expect(SelectionCardElement).toBeInTheDocument();
// expect(true).toBe(true);
});
and got error : Could not find "store" in the context of "Connect(ConnectedSelectionCard)". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(ConnectedSelectionCard) in connect options.'
import React from "react";
import { expect } from "#jest/globals";
import { render, screen, cleanup } from "#testing-library/react";
import M2SelectionCard from "../M2SelectionCard";
import { Provider } from "react-redux";
import configureStore from "../../redux/store";
const store = configureStore({});
it("test", () => {
render(
<Provider store={store}>
<M2SelectionCard />
</Provider>
);
const SelectionCardElement = screen.getByTestId("M2SelectionCardd");
expect(SelectionCardElement).toBeInTheDocument();
});
after that I added store to it in test (don't know should I add it here ?):
error message:
TypeError: Cannot read property 'selectionCard' of undefined
it points to className={classes.selectionCard}
any idea ?
TypeError: Cannot read property 'selectionCard' of undefined'
pointing to className={classes.selectionCard}
This error is saying that it cannot access a selectionCard property of an undefined object, classes in this case.
Given component under test:
function ConnectedSelectionCard({ classes }) {
...
return (
<Card data-testid="M2SelectionCardd" className={classes.selectionCard}>
<CardContent>
</CardContent>
</Card>
);
}
You should still pass all the expected props, i.e. a classes prop. For this purpose an empty object is sufficient enough to access into. In other words, if classes is an empty object then classes.selectionCard evaluates to undefined instead of throwing an error.
it("test", () => {
render(
<Provider store={store}>
<M2SelectionCard classes={{}} /> // <-- pass a classes prop
</Provider>
);
const SelectionCardElement = screen.getByTestId("M2SelectionCardd");
expect(SelectionCardElement).toBeInTheDocument();
});

Wrapping the app component with a context and getting the TypeError: (destructured parameter) is undefined

I'm trying to wrap all components under the app in a context to provide the things that I want
(as You can see it's my UserContext component)
enter code here
import React, { useState, createContext, useContext } from 'react'
const Context = createContext();
export let useUserContext = () => useContext(Context);
export default function UsersContext({ children }) {
const [users, setUsers] = useState();
const createUser = (user) => {
if (!user.name || !user.email || !user.password) return;
const newUsers = [...users, user];
setUsers(newUsers);
}
return (
<Context.Provider value={{ users, createUser }}>
{children}
</Context.Provider>
)
}
(it is my app component)
enter code here
import Nav from "./components/nav/Nav";
import Container from "./components/container/Container";
import { BrowserRouter } from "react-router-dom";
import UsersContext from "./components/contexts/UserContext";
function App() {
return (
<UsersContext>
<BrowserRouter>
<Nav />
<Container />
</BrowserRouter>
</UsersContext>
);
}
export default App;
It's used to be like this in my projects and I didn't have any problem but now
the error I'm getting "TypeError: (destructured parameter) is undefined" also says that it's because of the children in UserContext In my opinion it shouldn't happen maybe you can help me to find the problem I can't see.
Try: <Context.Provider value={[ users, { createUser } ]}>
instead of: <Context.Provider value={{ users, createUser }}>
edit:
also might try:
instead of
const newUsers = [...users, user];
setUsers(newUsers);
do
setUsers((currentUsers) => [...currentUsers, user]);
I found the problem. it was because of the useState. it was undefined and I was calling the property that related to useState at the UserContext.

useEffect not running at all when navigating to page with React Router

App.js:
import React, { Fragment } from "react";
import Header from "./components/Header";
import PostList from "./components/PostList";
import Post from "./components/Post";
import TagList from "./components/TagList";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
const App = () => {
return (
<Fragment>
<Router>
<Header />
<Switch>
<Route exact path="/" component={PostList} />
<Route path="/tags" component={TagList} />
<Route path="/posts/:id" component={Post} />
</Switch>
</Router>
</Fragment>
);
};
export default App;
Post.js:
import React, { useEffect, useState } from "react";
import Tag from "./Tag";
import { useParams } from "react-router-dom";
import axios from "axios";
const Post = () => {
const { id } = useParams();
const [post, setPost] = useState({});
useEffect(() => {
const fetchPost = async () => {
try {
const res = await axios.get(`/api/posts/${id}`);
setPost(res.data);
} catch (err) {
console.error(err);
}
};
fetchPost();
}, []);
return (
<div>
<h2>{post.title}</h2>
<p>{post.text}</p>
<div>
{post.tags.map((tag) => (
<Tag key={tag._id} tag={tag} />
))}
</div>
</div>
);
};
export default Post;
I'm trying to get the skeleton for a simple blog site up and running but I'm having issues with the Post component. When navigating to a specific post with the route '/posts/:id' the useEffect that's supposed to grab the post from my API doesn't seem to run, and inevitably I end up with a 'post.tags is undefined' error. Everything else is working correctly - API responds as expected to requests from Postman and 'useParams' is grabbing the post id from the URL just fine - it's just that the useEffect isn't running at all (console.logs aren't showing up either).
I've had no issues doing things this way in previous projects - in fact the useEffect in the TagList component is virtually identical and the /tags route works as expected, so I'm not sure what I'm missing?
useEffect runs only at first render, and then at any other render IF the dependencies specified have changed. Since you added there an empty array, those never change.
If you want useEffect to run again when the post id has changed, you need to add id as a dependency for useEffect.
useEffect(() => {
....
}, [id, setPost]);
also, your post.tags will still be undefined, because the data comes after the component has finished rendering so you should actually check before that return if you have post data and if you don't have post data, to return null or a loading skeleton.

why my context doesn't update when the context value updates?

so I am using React's context API in my Gatsby app(which is written in React basically) to deal with user authentication. I have two components that use that context: dashboard and navBar. When I try to log in and log out, my navBar will behave differently according to my userContext, but my dashboard won't respond. Is it something related to the structure, like navBar is the direct "children" to layout, but dashboard is not? I assume not though, after all, that's why I use contextAPI then just pass a normal prop.
Here are the codes:
//layout.js
import React, { useContext, useState, createContext } from "react"
import Navbar from "../components/navBar"
import {monitorAuth} from "../firebase/firebaseService"
export const UserStateContext = createContext(null)
export const SetUserContext = createContext()
const Layout = ({ children }) => {
const [user, setUser] = useState()
console.log(user)
monitorAuth(setUser)// everytime a layout component renders, it will grab a user if it is logged inthen setUser, then I will use it in the context
return (
<>
<UserStateContext.Provider value={user}>
<SetUserContext.Provider value={setUser}>
<div>
<SEO />
<Navbar />
<main>{children}</main>
</div>
</SetUserContext.Provider >
</UserStateContext.Provider>
</>
)
}
export default Layout
import React, { useState, useContext } from "react"
import AppBar from "#material-ui/core/AppBar"
import { signOut } from "../firebase/firebaseService"
import {UserStateContext} from "./layout"
export default function NavBar() {
const user = useContext(UserStateContext)
console.log(user) // when I log in/ log out, it will console.log the right user status, user/null
const renderMenu = () => {
return (
<>
{user? (
<>
<Button onClick={signOut}>Sign Out</Button>
<Button>My profile</Button>
</>)
:<Button>Sign In</Button> }
</>
)
}
return (
<AppBar position="static" className={classes.root}>
...
{renderMenu()}
...
</AppBar>
)
}
//dashboard.js
import React, { useContext } from 'react'
import Layout from '../components/layout'
import LoggedIn from '../components/dashboard/loggedIn'
import NotLoggedIn from '../components/dashboard/notLoggedIn'
import {UserStateContext} from "../components/layout"
const Dashboard = props => {
console.log("within dashboard")
const user = useContext(UserStateContext)
console.log(user)
const renderDashboard = () =>{
return (
<>
{user? <LoggedIn /> : <NotLoggedIn />}
</>
)
}
return(
<Layout>
{renderDashboard()}
</Layout>
)
}
export default Dashboard
One more clue, I console.log user in all three components and when I refresh the page:
within dashboard
dashboard.js:17 null
layout.js:15 undefined
navBar.jsx:54 undefined
layout.js:15 [user...]
navBar.jsx:54 [user...]
layout.js:15 [user...]
That means, at first, user is not set yet, so all three components log the user as undefined, but later, layout detect the user and then updates it, so navbarknows too, but dashboard doesn't. Is it something about re-render? Thanks!
The reason it's not working is because your <Dashboard> component is not a child of the context provider. If you use React devtools, you'll see the component tree looks like
<Dashboard>
<Layout>
<UserStateContext.Provider>
<SetUserContext.Provider>
...
</SetUserContext.Provider>
</UserStateContext.Provider>
</Layout>
</Dashboard>
When the context value changes, it looks for components in its subtree that useContext. However, Dashboard is not a child, it's the parent!
If you want to follow this pattern, a solution may be to create a parent component of Dashboard and put the context there.

Categories