skip to Main Content

I am using vite, TS to created a react component library.

My main.tsx in component-library contains the following test component,

import React, { useState } from "react";

export const TestComponent = () => {
  console.log("CONTENT-TEST");
  const [yamlTemplate, setYamlTemplate] = useState<string>("test component");
  console.log("CONTENT", yamlTemplate);
  console.log("CONTENT-setTemplate", setYamlTemplate);

  return <div>Test Component</div>;
};

The library build is created using tsc && vite build and installed to an actual React project using npm install --save ../component-library. Upon running the project I get the following error,

dispatcher is null
useState@http://localhost:3000/static/js/bundle.js:2823:7
Qr@http://localhost:3000/static/js/bundle.js:46064:67
renderWithHooks@http://localhost:3000/static/js/bundle.js:22917:31

Its complaining on useState. However I am able to see the log CONTENT-TEST in the logs. Here is the code to the react app project,

import "./App.css";
import { TestComponent } from "component-library";

function App() {
  return (
    <div className="App">
      <TestComponent />
    </div>
  );
}

export default App;

Can anyone please help resolve this issue?


EDIT: I should also mentioned that my react app is a javascript react project and not using TS and vite. It was created through CRA

Here is my vite config,

import { defineConfig } from "vite";
import dts from "vite-plugin-dts";
import { libInjectCss } from "vite-plugin-lib-inject-css";
import react from "@vitejs/plugin-react";
import path, { extname, relative, resolve } from "path";
import { fileURLToPath } from "node:url";
import { glob } from "glob";

export default defineConfig({
  build: {
    copyPublicDir: false,
    lib: {
      entry: resolve(__dirname, "src/index.tsx"),
      formats: ["cjs", "es"],         
    },
    rollupOptions: {
      external: ["react", "react-dom"], 
      input: Object.fromEntries(
        glob
          .sync("src/**/*.{ts,tsx}", {
            ignore: ["src/**/*.d.ts"],
          })
          .map((file) => [
            relative("src", file.slice(0, file.length - extname(file).length)),
            fileURLToPath(new URL(file, import.meta.url)),
          ]),
      ),
      output: {
        assetFileNames: "assets/[name][extname]",
        entryFileNames: "[name].js",
        globals: {
           react: 'React',
          'react-dom': 'ReactDOM',
         },
      },
    },
    sourcemap: true, 
    emptyOutDir: true, 
  },
  plugins: [react(), libInjectCss(), dts({ include: ["src"] })],    });

Here are the peer dependencies form package.json. These dependencies have the same version as the CRA react app project,

 "peerDependencies": {
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  },

2

Answers


  1. Chosen as BEST ANSWER

    What worked for me was to create a React app with npm create vite@latest. One main difference is I am using TS and vite in this case and this seems to be compatible somehow and worked. I might actually check creating a React app with vite and JS and see if it works. If it works then the possible issue is in the packages installed by CRA as its dependencies.


    1. We can check same react version in both component-library and main-react-app
      Check for peerDependency in component library package.json
    {
      "peerDependencies": {
        "react": "^17.0.0",
        "react-dom": "^17.0.0"
      }
    }
    

    And then we can validate this version is same in main react-app

    {
      "dependencies": {
        "react": "^17.0.0",
        "react-dom": "^17.0.0"
      }
    }
    
    1. We can re-install dependencies in both npm install

    2. In Component Library we can check React is marked as an external dependency in component library to avoid bundling it multiple times
      We can do so in vite.config.ts for the component library

    import { defineConfig } from 'vite';
    import react from '@vitejs/plugin-react';
    import dts from 'vite-plugin-dts';
    
    export default defineConfig({
      plugins: [react(), dts()],
      build: {
        lib: {
          entry: 'src/main.tsx',
          name: 'ComponentLibrary',
          fileName: (format) => `component-library.${format}.js`,
        },
        rollupOptions: {
          external: ['react', 'react-dom'],
          output: {
            globals: {
              react: 'React',
              'react-dom': 'ReactDOM',
            },
          },
        },
      },
    });
    
    1. We can check for duplicates by one of two ways below –
      i. Run npm dedupe
      ii. Use Aliases in Webpack
    resolve: {
      alias: {
        react: path.resolve('./node_modules/react'),
      },
    }
    

    After making these changes we can rebuild component library and reinstall it in the main application.

    Reference for additional checks: https://github.com/facebook/react/issues/30520

    https://www.dhiwise.com/post/how-to-resolve-the-error-react-dispatcher-is-null

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search