Reputation: 36225
I have a NextJS project was running NextJS 12 and I have my own library that I have imported locally for dev work, this library contains some helper functions and re-usable components that I can use in all of my projects.
This works fine in NextJS 12 but have tried upgrading NextJS 13 and then I hit this error where if I include a component from the library, I get the Cannot read properties of null (reading
useState)
As a test, I created a brand new NextJS project (although this time it's 14) with a brand new library.
I create a function in the library and use in my new test project and it works perfectly fine.
I add a component to the library and import it into my test project, no errors or warnings but then when I run it I get the below (same error as above in more details)
My NextJS project package.json
is below:
{
"name": "new-nextjs-project",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"new-nextjs-library": "file:../new-nextjs-library",
"next": "13.5.6",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.0.1",
"postcss": "^8",
"tailwindcss": "^3.3.0",
"typescript": "^5"
}
}
My tsconfig.json
is below:
{
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"paths": {
"@/*": [
"./src/*"
]
},
"forceConsistentCasingInFileNames": true,
"target": "es5"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
}
My test library package.json
is below:
{
"name": "new-nextjs-library",
"version": "1.0.0",
"description": "",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"/dist"
],
"script": {
"build": "tsc"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.0.1",
"postcss": "^8",
"react": "^18",
"react-dom": "^18",
"tailwindcss": "^3.3.0",
"typescript": "^5"
}
}
My library tsconfig.json
is below:
{
"compilerOptions": {
"module": "commonjs",
//"target": "es2015",
"declaration": true,
"lib": ["esnext", "dom"],
"outDir": "./dist",
"rootDir": "./src",
"jsx": "react",
"strict": false,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"target": "ES2018",
"noEmitOnError": true,
"downlevelIteration": true,
"incremental": true
},
"include": [
"src/**/*"
]
}
In my src/classes
folder I have a file called sayHello
which includes the following code which works fine in my main test project
export const sayHello = (firstName: string, lastName: string) => {
return `${firstName} ${lastName}`
}
My component in my library is below, this is located in /src/components
"use client"
import React, { useState } from 'react';
const Clicker = () => {
const [clickCount, setClickCount] = useState(0);
return (
<>
<button type='button' onClick={() => setClickCount(prev => prev++)}>
Click
</button>
<p>
You've clicked {clickCount}
</p>
</>
)
}
export default Clicker
Note I tried adding use client at the top in case it was something to do with server side components in the new NextJS but doesn't make any difference
My library index.ts
file is below:
import React from "react";
//Components
import Clicker from "./components/Clicker";
//Classes
import {sayHello} from "./classes/sayHello";
export {
Clicker,
sayHello
}
I'm importing the component and using it in my main app as below
import React from "react";
import {NextPage} from "next";
import {Clicker, sayHello} from "new-nextjs-library";
const HomePage : NextPage = () => {
return (
<>
<h1>My New Page</h1>
<p>Hello {sayHello("Chris", "Board")}</p>
<Clicker />
</>
)
}
export default HomePage;
In the browser console I see the following (added as an image as it didn't format very nicely:
How am I doing an invalid hook, the only hook I'm using is the useState
within the functional component is valid.
How can I get this:
cannot read properties of null reading
useState
.
This makes no sense, and I say this approach has worked on NextJS, but NextJS 13 or 14 I hit this problem.
Upvotes: 2
Views: 323
Reputation: 36225
I finally figured the problem.
I had to change my next.config.js file to be called next.config.mjs.
I then had to add the following to this file:
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
config.resolve.alias["react"] = path.resolve("./node_modules/react");
return config;
}
The complete file looks like the below
import path from "path";
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
config.resolve.alias["react"] = path.resolve("./node_modules/react");
return config;
}
};
export default nextConfig;
I'm not entirely sure why I have to do this now, npm list react only showed one version of react in the project but as soon as this section was added to the next config and restarted, the library started working again.
Upvotes: 1