I have built a simple website with NextJS (Typescript) Front-end and Express back-end (also Tailwind config). Everything was working fine until I tried to incorporate react-scroll-parallax and since I have received the following message:
(“unhandled runtime error: Typeerror: cannot read properties of null (reading ‘useRef’))
Steps I have taken to fix include:
- I have tried to dynamically imported Parralaxprovider to try to make it run only on the client-side
- I have tried to wrap the parralax-related code in ‘useEffect’
- I have checked that ParallaxProvider is wrapped around entire application in _app.tsx
- I have removed ‘node_modules’ and ‘package.json’, cleared npm cache and reinstalled dependencies
- I am searched for this issue on other posts on StackOverflow. There are others who have had the same issue, which I have tried to draw from, but I am struggling to apply to my context (probably because I am still quite new to using NextJS).
I have a few components rendered on a page “Index.tsx” but to start I am currently trying to apply a parallax scrolling effect to one component “container”. I have attached my code below. I am new to NextJS as well as using parallax effect so any advise would be welcome.
_app.tsx
import React, { ReactNode, useEffect, useRef } from 'react';
import { useParallax } from 'react-scroll-parallax';
interface ContainerProps {
children: ReactNode;
bgColor?: string;
maxWidth?: string;
backgroundImage?: string;
backgroundOpacity?: number;
}
const Container: React.FC<ContainerProps> = ({
children,
bgColor = 'bg-white',
maxWidth = 'max-w-3xl',
backgroundImage,
backgroundOpacity = 0.8,
}) => {
const parallaxRef = useRef(null);
useEffect(() => {
// Ensure the parallax effect is applied only on the client-side
const { ref } = useParallax({ speed: -30 });
parallaxRef.current = ref.current;
}, []);
return (
<div ref={parallaxRef} className={`relative ${bgColor} ${maxWidth} mx-auto p-4`}>
{backgroundImage && (
<div
className="absolute inset-0 bg-cover bg-center z-0 fixed-background"
style={{
backgroundImage: `url(${backgroundImage})`,
opacity: backgroundOpacity,
}}
/>
)}
<div className="relative z-10">
{children}
</div>
</div>
);
};
export default Container;
Container.tsx
import React, { ReactNode } from 'react';
import { useParallax } from 'react-scroll-parallax';
interface ContainerProps {
children: ReactNode;
bgColor?: string;
maxWidth?: string;
backgroundImage?: string;
backgroundOpacity?: number;
}
const Container: React.FC<ContainerProps> = ({
children,
bgColor = 'bg-white',
maxWidth = 'max-w-3xl',
backgroundImage,
backgroundOpacity = 0.8,
}) => {
const parallax = useParallax({ speed: -30 });
return (
<div ref={parallax.ref} className={`relative ${bgColor} ${maxWidth} mx-auto p-4`}>
{backgroundImage && (
<div
className="absolute inset-0 bg-cover bg-center z-0 fixed-background"
style={{
backgroundImage: `url(${backgroundImage})`,
opacity: backgroundOpacity,
}}
/>
)}
<div className="relative z-10">
{children}
</div>
</div>
);
};
export default Container;
index.tsx
import { useEffect, useState } from 'react';
import Header from '../components/Header';
import ScrollDownMessage from '../components/ScrollDownMessage';
import MainContent from '../components/MainContent';
import Container from '../components/Container';
import { fetchData } from '../services/api';
interface DataItem {
id: number;
name: string;
}
const HomePage: React.FC = () => {
const [data, setData] = useState<DataItem[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const getData = async () => {
try {
const data = await fetchData();
setData(data);
} catch (error: any) {
setError(error.message);
console.error('Error fetching data:', error);
} finally {
setLoading(false);
}
};
getData();
}, []);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<div className="flex items-center justify-center min-h-screen bg-gray-100 overflow-hidden">
<Container maxWidth="max-w-7xl" backgroundImage="/images/Background-image.jpg" backgroundOpacity={0.5}>
<div className="flex flex-col items-center justify-center min-h-screen">
<Header />
<ScrollDownMessage />
</div>
<MainContent />
<div>
<h2>Fetched Data:</h2>
{Array.isArray(data) && data.map((item) => (
<div key={item.id}>
<p>{item.name}</p>
{/* Display other fields as needed */}
</div>
))}
</div>
</Container>
</div>
);
};
export default HomePage;
user25308631 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.