Reputation: 876
I try to change the state of my cursor in a Next.js app with useContext
but got this error :
TypeError: Cannot destructure 'Object(...)(...)' as it is undefined.
The state should change to isActive: true
when hover the button
My ContextProvider :
import { createContext, useState } from "react";
export const CursorContext = createContext();
const CursorContextProvider = ({ children }) => {
const [cursor, setCursor] = useState({ active: false });
return (
<CursorContext.Provider value={[cursor, setCursor]}>
{children}
</CursorContext.Provider>
);
};
export default CursorContextProvider;
in the App :
import App from "next/app";
import Head from "next/head";
import Layout from "../components/Layout";
import CursorContextProvider from "../components/CursorContextProvider";
import Cursor from "../components/Cursor";
import { getCategories } from "../utils/api";
import "../styles/index.css";
import "../styles/style.scss";
const MyApp = ({ Component, pageProps, children }) => {
return (
<Layout categories={pageProps.categories}>
<Head>
<link rel="preconnect" href="https://app.snipcart.com" />
<link rel="preconnect" href="https://cdn.snipcart.com" />
<link
rel="stylesheet"
href="https://cdn.snipcart.com/themes/v3.0.16/default/snipcart.css"
/>
<script src="https://cdn.snipcart.com/themes/v3.0.16/default/snipcart.js" />
</Head>
<CursorContextProvider>
<Cursor />
{children}
</CursorContextProvider>
<Component {...pageProps} />
</Layout>
);
};
// getInitialProps disables automatic static optimization for pages that don't
// have getStaticProps. So [[...slug]] pages still get SSG.
// Hopefully we can replace this with getStaticProps once this issue is fixed:
// https://github.com/vercel/next.js/discussions/10949
MyApp.getInitialProps = async (ctx) => {
// Calls page's `getInitialProps` and fills `appProps.pageProps`
const appProps = await App.getInitialProps(ctx);
// Fetch global site settings from Strapi
const categories = await getCategories();
// Pass the data to our page via props
return { ...appProps, pageProps: { categories, path: ctx.pathname } };
};
export default MyApp;
Here my Cursor component :
import React, { useContext } from "react";
import useMousePosition from "./useMousePosition";
import { CursorContext } from "./CursorContextProvider";
const Cursor = () => {
const { clientX, clientY } = useMousePosition();
const [cursor] = useContext(CursorContext);
return (
<div
style={{
position: "fixed",
top: 0,
bottom: 0,
left: 0,
right: 0,
zIndex: 9999,
pointerEvents: "none"
}}
>
<svg
width={50}
height={50}
viewBox="0 0 50 50"
style={{
position: "absolute",
left: clientX,
top: clientY,
transform: `translate(-50%, -50%) scale(${cursor.active ? 2.5 : 1})`,
stroke: cursor.active ? "black" : "white",
strokeWidth: 1,
fill: cursor.active ? "rgba(255,255,255,.5)" : "black",
transition: "transform .2s ease-in-out",
}}
>
<circle
cx="25"
cy="25"
r="8"
/>
</svg>
</div>
);
};
export default Cursor;
And a test Button component :
import { useContext, useCallback } from "react";
import { CursorContext } from "./CursorContextProvider";
const Button = () => {
const [, setCursor] = useContext(CursorContext);
const toggleCursor = useCallback(() => {
setCursor(({ active }) => ({ active: !active }));
});
return (
<button
type="button"
style={{ padding: "1rem" }}
onMouseEnter={toggleCursor}
onMouseLeave={toggleCursor}
>
HOVER ME
</button>
);
};
export default Button;
Do you see where I did something wrong to make the setState
undefined ?
Upvotes: 1
Views: 2638
Reputation: 50278
This is most likely due to your CursorContextProvider
not wrapping the component where Button
is being used. Try moving it to the top of your returned JSX in App
.
const MyApp = ({ Component, pageProps, children }) => {
return (
<CursorContextProvider>
<Layout categories={pageProps.categories}>
//...
</Layout>
</CursorContextProvider>
);
};
Upvotes: 1