Getting error: You must pass a component to the function returned by connect

30 views Asked by At

I have been updating all my Babel and Webpack dependencies to remove vulnerabilities. Currently, my package.json file looks like this and it installs all dependencies perfectly:

{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"watch": "webpack --watch",
"test": "jest --coverage --config ./jest.config.js",
"test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand",
"test:watch": "npm run test -- --watch",
"test:watchAll": "npm run test -- --watchAll",
"test:updateSnapshot": "jest --updateSnapshot"
},
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.8.1",
"core-js": "^3.36.0",
"dom-to-image": "2.6.0",
"i18n-react": "0.6.4",
"immutable": "^4.0.0-rc.12",
"jquery": "^3.4.1",
"mime-types": "latest",
"prop-types": "latest",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-redux": "^7.2.2",
"react-select": "3.0.4",
"react-svg": "^10.0.14",
"react-webcam": "^5.2.0",
"reactjs-popup": "^1.4.2",
"redux": "4.2.0",
"redux-logger": "3.0.6",
"redux-promise-middleware": "6.1.2",
"redux-thunk": "^2.4.1"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/eslint-parser": "^7.0.0",
"@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/plugin-proposal-decorators": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"babel-jest": "^29.7.0",
"babel-loader": "^9.0.0",
"babel-plugin-react-html-attrs": "^3.0.5",
"babel-plugin-rewire": "^1.0.0",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.10.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"enzyme-to-json": "^3.4.3",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.0.0",
"jest": "^29.7.0",
"less": "^4.2.0",
"less-loader": "^11.1.0",
"react-hot-loader": "4.8.4",
"style-loader": "^3.3.4",
"url-loader": "^4.0.0",
"webpack": "^5.76.0",
"webpack-cli": "^5.0.0",
"webpack-dev-server": "^5.0.0"
}
}

I am configuring through the webpack-config.js file, and it looks like this:

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const Copy
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');

const config = {
js: {
srcDir: 'src/main/javascript',
resourceDir: 'src/main/resources',
src: ./main.jsx,
outputDir: './target/classes/static/',
outputFile: 'bundle.js',
},
};

const debug = process.env.NODE_ENV !== 'production';

const modules = [];
modules.push(config.js.srcDir);
const modulesWithNode = modules.slice();
modulesWithNode.push('node_modules');

module.exports = {
mode: debug ? 'development' : 'production',
context: path.join(__dirname, config.js.srcDir),
devtool: debug ? 'source-map' : 'hidden-source-map',
entry: {
app: [config.js.src],
},
output: {
filename: config.js.outputFile,
publicPath: '/',
path: path.join(__dirname, config.js.outputDir),
sourceMapFilename: 'prod-[file].map',
},
resolve: {
modules: modulesWithNode,
extensions: ['.js', '.jsx'],
fallback: { path: false },
},
module: {
rules: [
{
test: /.jsx?$/,
include: modules.map(module => path.resolve(__dirname, module)),
use: {
loader: 'babel-loader',
options: {
presets: [['@babel/preset-env', { useBuiltIns: 'entry', corejs: 3 }], '@babel/preset-react'],
plugins: [['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }], '@babel/plugin-proposal-class-properties'],
retainLines: true,
},
},
},
{
test: /.less$/,
include: modules.map(module => path.resolve(__dirname, module)),
use: [
{ loader: 'style-loader'},
{ loader: 'css-loader', options: { sourceMap: debug } },
{ loader: 'less-loader', options: { sourceMap: debug } }
],
},
{
test: /.(jpg|png|woff|woff2|eot|ttf|svg|wav)$/,
use: 'url-loader?limit=100000'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html',
inject: 'body'
}),
new CopyWebpackPlugin({
patterns: [
{
context: '../resources',
from: './static/assets/sounds/camera-shutter-sound.wav',
to: 'assets/sounds',
toType: 'dir',
},
{
from: './sw',
to: './',
},
]
}),
]
};

I am using Node version 20.11.0 and npm version 10.2.4. When I install all the dependencies through Maven, I don't get any errors. However, when I start my application through Spring Boot and deploy the frontend, I always receive this error on browser console:

Uncaught Error: You must pass a component to the function returned by connect. Instead received {"kind":"class","elements":[{"kind":"method","key":"render","placement":"prototype","descriptor":{"writable":true,"configurable":true,"enumerable":false}}]}

I assume it has something to do with the configuration of the decorators, which is causing this condition in the connectAdvanced.js file of react-redux, as I haven't made any changes to the code.

error on browser console

I have been trying to configure decorators in so many ways, but none worked. I expect to load all components on my page without errors.

1

There are 1 answers

0
Tolgahan Dayanıklı On

The issue seems to be how Babel is transpiling your JS code, specifically regarding the use of the decorators with React components.

When using the @babel/plugin-proposal-decorators plugin, the order of plugins matters, especially when used in conjunction with the @babel/plugin-proposal-class-properties plugin. The decorators proposal has had several iterations, and the syntax and semantics have changed over time, so it's crucial that Babel plugins are correctly configured.

You can try to change the order of the plugins. The @babel/plugin-proposal-decorators should come before the @babel/plugin-proposal-class-properties plugin in your Babel configuration array. Moreover, if you are using the legacy mode for decorators (common in React projects), you need to set the legacy: true option for the decorators plugin and loose: true for class properties:

plugins: [
    ['@babel/plugin-proposal-decorators', { legacy: true }],
    ['@babel/plugin-proposal-class-properties', { loose: true }]
]

This setup is important because the legacy: true option enables the use of the older decorator syntax, which is what most React and Redux codebases that use decorators require.

After you change their orders and add the legacy/loose pair, you should run the commands:

rm -rf node_modules
rm package-lock.json
npm install