Invalid Hook Call within ReactJS Crash Course for beginners - reactjs

I'm trying to follow along with this youtube video https://youtu.be/tbvguOj8C-o?t=33570
I'm having issue at this point forward in the video until the next code update (Roughly one minute in)
Specifically, the creator is adding these changes which causes an Invalid Hook Call
import RadioButtonUncheckedIcon from '#mui/icons-material/RadioButtonUnchecked';
...
const capture = useCallback(() => {
const imageSrc = webcamRef.current.getScreenshot();
console.log(imageSrc);
}, [webcamRef]);
...
<RadioButtonUncheckedIcon
className='WebcamCapture__button'
onClick={capture}
/>
The full code for the file is here:
import React, {useCallback, useRef} from "react";
import Webcam from "react-webcam";
import RadioButtonUncheckedIcon from '#mui/icons-material/RadioButtonUnchecked';
const videoConstraints = {
width: 250,
height: 400,
facingMode: "user",
};
function WebcamCapture() {
const webcamRef = useRef(null);
const capture = useCallback(() => {
const imageSrc = webcamRef.current.getScreenshot();
console.log(imageSrc);
}, [webcamRef]);
return (
<div className="webcamCapture">
<Webcam
audio={false}
height={videoConstraints.height}
ref={webcamRef}
screenshotFormat="image/jpeg"
width={videoConstraints.width}
videoConstraints={videoConstraints}
/>
<RadioButtonUncheckedIcon
className='WebcamCapture__button'
onClick={capture}
/>
</div>
);
}
export default WebcamCapture;
The WebcamCapture component is used here:
import React from 'react';
import WebcamCapture from './WebcamCapture';
function App() {
return (
<div className="app">
<h1>Test build</h1>
<WebcamCapture />
</div>
);
}
export default App;
The error code displayed in the chrome console is this:
Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
This is my best guess for the issue. It's the first issue called that causes declerations to be null. The full error stacktrace can be found here: https://pastebin.com/UKQm9TYi
The package.json looks like this,
{
"name": "snapchat-clone",
"version": "0.1.0",
"private": true,
"dependencies": {
"#mui/base": "^5.0.0-alpha.91",
"#mui/icons-material": "^5.8.4",
"#mui/material": "^5.9.2",
"#reduxjs/toolkit": "^1.8.3",
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^13.3.0",
"#testing-library/user-event": "^14.3.0",
"react": "^16.8.0",
"react-dom": "16.8.0",
"react-redux": "^8.0.2",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
To the best of my knowledge, React and the renderer are matching versions, I haven't violated the Rules of Hooks (most tentative!), and there is only one copy of React running in the app as every other call is dedupped.
I'm very new to React and Node.JS so any feedback or criticisms are welcome. Thank you for your time.

I found the issue to the problem. There was a missing dependency in the package.json that I hadn't noticed until I placed the code into a sandbox.
Specifically, it was
"#mui/icons-material": "5.8.4",

Related

glide-data-grid / custom-cell-editing / The above error occurred in the <Editor> component / Invalid hook call

Trying to locally test Dropdown cell editing based on https://glideapps.github.io/glide-data-grid/?path=/story/extra-packages-cells--custom-cell-editing
Grid with cells rendered appropriately.
However, clicking on a cell to choose value from Dropdown, crashes and produces:
The above error occurred in the <Editor> component:
at Editor (http://localhost:3000/static/js/bundle.js:67391:12)
at div
at div
at render (http://localhost:3000/static/js/bundle.js:68194:13)
....
"above error" is
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for
one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
Code extracted and changed from https://github.com/glideapps/glide-data-grid/blob/8085cd8e0d04c865ab5963af961b734fb053ded9/packages/cells/src/cell.stories.tsx:
import * as React from 'react';
import DataEditor, {
GridCellKind,
DataEditorProps
} from "#glideapps/glide-data-grid";
import { useExtraCells, DropdownCell as DropdownRenderer, DropdownCellType } from "#glideapps/glide-data-grid-cells";
import type { DropdownCell } from "#glideapps/glide-data-grid-cells";
import "#glideapps/glide-data-grid/dist/index.css";
const defaultProps: Partial<DataEditorProps> = {
smoothScrollX: true,
smoothScrollY: true,
isDraggable: false,
rowMarkers: "none",
width: "100%",
};
export const CustomCellEditing: React.VFC = () => {
const cellProps = useExtraCells();
const data = React.useRef<string[]>([]);
return (
<DataEditor
{...defaultProps}
{...cellProps}
onPaste={true}
onCellEdited={(cell, newVal) => {
if (newVal.kind !== GridCellKind.Custom) return;
if (DropdownRenderer.isMatch(newVal)) {
data.current[cell[1]] = newVal.data.value;
}
}}
getCellsForSelection={true}
getCellContent={cell => {
const [, row] = cell;
const val = data.current[row] ?? "A";
return {
kind: GridCellKind.Custom,
allowOverlay: true,
copyData: val,
data: {
kind: "dropdown-cell",
allowedValues: ["A", "B", "C"],
value: val,
},
} as DropdownCellType;
}}
columns={[
{
title: "Dropdown",
width: 200,
},
]}
rows={5}
/>
);
};
export default CustomCellEditing;
index.html body last element:
<div id="portal" />
Config:
{
"name": "xp-ts-mui",
"version": "0.1.0",
"private": true,
"dependencies": {
"#emotion/react": "^11.10.4",
"#emotion/styled": "^11.10.4",
"#glideapps/glide-data-grid": "^5.2.1",
"#glideapps/glide-data-grid-cells": "^5.2.1",
"#mui/icons-material": "^5.10.3",
"#mui/material": "^5.10.3",
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^13.3.0",
"#testing-library/user-event": "^13.5.0",
"#types/jest": "^27.5.2",
"#types/node": "^16.11.46",
"#types/react": "^18.0.15",
"#types/react-dom": "^18.0.6",
"lodash": "^4.17.21",
"marked": "^4.2.12",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-responsive-carousel": "^3.2.23",
"react-scripts": "5.0.1",
"styled-components": "^5.3.6",
"typescript": "^4.7.4",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Initial rendering success as:
Crashes when clicking Dropdown cell for selection as:
Extracted and tested another from same https://github.com/glideapps/glide-data-grid/blob/8085cd8e0d04c865ab5963af961b734fb053ded9/packages/cells/src/cell.stories.tsx example based on https://glideapps.github.io/glide-data-grid/?path=/story/extra-packages-cells--custom-cells
All other Custom Cells (e.g. Tag, DatePicker) are working fine with respective editors.
Normal behavior of Tag:
and DatePicker:
Only DropdownCell crashes when clicking for selection.
Any advice please?

renderHook causes `TooManyRerenders` error when changing state

I want to test a hook that uses states in its implementation, but each time I run my tests I get this error:
Error: Uncaught [Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.]
The hook is complex and I couldn't find which part may cause an issue (plus it works perfectly fine under real conditions, when running the application with npm start).
I tried to write a dummy test to see if I could figure out anything, and I found that updating a state (which I do in my hook) triggers the error.
Basically, this fails:
import { renderHook } from "#testing-library/react";
import React from "react";
it("foo test", () => {
const { result } = renderHook(() => {
const [foo, setFoo] = React.useState("foo");
setFoo("bar"); // This line is the culprit
return foo;
});
expect(result.current).toEqual("bar");
});
But this works:
import { renderHook } from "#testing-library/react";
import React from "react";
it("foo test", () => {
const { result } = renderHook(() => {
const [foo, setFoo] = React.useState("foo");
return foo;
});
expect(result.current).toEqual("foo");
});
What is the reason for this error and how can I fix it ?
Also, my package.json file:
{
"name": "agora-front",
"version": "0.1.0",
"private": true,
"dependencies": {
"#emotion/react": "^11.10.0",
"#emotion/styled": "^11.10.0",
"#mui/icons-material": "^5.8.4",
"#mui/material": "^5.9.3",
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^13.3.0",
"#types/react": "^18.0.15",
"#types/react-dom": "^18.0.6",
"i18next": "^21.8.16",
"i18next-browser-languagedetector": "^6.1.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^11.18.3",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"typescript": "^4.7.4",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "BROWSER=none react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --verbose",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"#babel/preset-typescript": "^7.18.6",
"#types/jest": "^28.1.6",
"jest": "^28.1.3",
"prettier": "2.7.1",
"react-test-renderer": "^18.2.0"
}
}
I got tricked by the test environment and forgot React basic good practices.
Every state update should be wrapped in a condition with useEffect, otherwise render will trigger endlessly.
I followed that practice in all my React components, thus explaining why it was working fine when building the application. But I wrote my tests a bit quickly.
For my quick example, this is the correct way to do it:
import { renderHook } from "#testing-library/react";
import React from "react";
it("foo test", () => {
const { result } = renderHook(() => {
const [foo, setFoo] = React.useState("foo");
React.useEffect(() => {
setFoo("bar"); // Now it works.
}, [])
return foo;
});
expect(result.current).toEqual("bar");
});

How to connect mongoDB in react

Such a problem that when I try to simply connect mongoDB in react
import React, {Component} from 'react';
export default class App extends Component{
componentDidMount(){
const {MongoClient} = require('mongodb');
const client = new MongoClient('mongodb+srv://dafu4k:****#cluster0.jd26aac.mongodb.net/?retryWrites=true&w=majority');
const start = async () => {
try{
await client.connect();
console.log('Connected')
}
catch(e){
console.log(e)
}
}
start();
}
render(){
return (
<>
<h1>Home page</h1>
</>
)
}
}
Errors of the same type appear in the browser itself
Module not found: Error: Can't resolve 'os' in 'C:\Users\DaFu4\OneDrive\Рабочий >стол\mongotest\mongo-test\node_modules\ip\lib'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
add a fallback 'resolve.fallback: { "os": require.resolve("os-browserify/browser") }'
install 'os-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "os": false }
They differ in that the last line has different keys (timers,crypto,http, etc.)
I watched how to connect mongoDB to react, everywhere they used a certain mongoose along with mongoDB, but I can’t understand, maybe it’s required to connect to react, or am I still doing something wrong? (in normal js everything works fine, the code has not changed)
src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
package.json
{
"name": "mongo-test",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^13.3.0",
"#testing-library/user-event": "^13.5.0",
"crypto-browserify": "^3.12.0",
"mongodb": "^4.7.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
We can not connect React JS to MongoDB because things don’t work like this.
First, we create a react app, and then for backend maintenance, we create API in node.js and express.js which is running at a different port and our react app running at a different port. for connecting React to the database (MongoDB) we integrate through API.
Check this link:
[1]: https://www.geeksforgeeks.org/how-to-connect-mongodb-with-reactjs/#:~:text=First%2C%20we%20create%20a%20react,MongoDB)%20we%20integrate%20through%20API.
React is not communicating directly with MONGODB (via mongoose). It interacts with nodejs/express which is the one to communicate with MONGODB.
The explanation for the steps are presented in what I find to be the clearest form, in MERN STACK TUTORIAL (MERN = Mongodb, Express, React and Nodejs),
especially as the most essential part doesn't exist in Geeks4Geeks' tutorial (the part where they show you an example code of index.html).
Good luck!

How to import styles into React for Material Components for Web

I'm creating my own React components for Google's Material Components for Web. I'm trying to get the styling to work. According to the docs, you need to add the following to your sass file:
#use "#material/button";
// #include button.core-styles;
Note: I think there is a bug in the docs - button.core-styles doesn't exist. I just commented it out.
When the button renders, it has all the classes on the element, but all the styles associated with those classes are missing. So it doesn't look like an MDC button.
I found this bug report, which lead me to try this:
#import "#material/button/mdc-button";
And voila! The button is styled!
Can someone explain to me what the difference is between the #use and #import options? And why I would use one over the other?
Full example:
Button.scss
#import "~#material/button/mdc-button";
Button.js
import './Button.scss';
import {useEffect, useRef} from 'react';
import {MDCRipple} from '#material/ripple';
function Button(props) {
const buttonElement = useRef(null);
useEffect(() => {
const ripple = new MDCRipple(buttonElement.current);
return () => {
ripple.destroy();
}
});
return (
<button className="mdc-button mdc-button--raised" ref={buttonElement}>
<span className="mdc-button__ripple"></span>
<span className="mdc-button__label">{props.children}</span>
</button>
);
}
export default Button;
package.json
{
"name": "button-test",
"version": "0.1.0",
"private": true,
"dependencies": {
"#material/button": "^12.0.0",
"#material/ripple": "^12.0.0",
"#material/theme": "^12.0.0",
"#testing-library/jest-dom": "^5.14.1",
"#testing-library/react": "^11.2.7",
"#testing-library/user-event": "^12.8.3",
"install": "^0.13.0",
"npm": "^7.20.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"sass": "^1.37.5",
"web-vitals": "^1.1.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Ugh. I just found this bug report. But the material.io website still has old info on it....
When I use:
#use "~#material/button/styles";
The button is now styled.

How do I get past the Typescript error "Cannot find name 'module'?"

I've looked at the resolutions for similar problems here, but they all appear to deal with pre-existing modules. This is happening to a React Component I wrote myself, and I'm not sure how to get around it.
import React from 'react';
import { useForm } from "react-hook-form"
import axios from 'axios'
export default FileUploadForm = () => {
const { register, handleSubmit, /* errors */ } = useForm()
const onSubmit = (data: string | Blob) => {
console.log(data)
const formData = new FormData();
formData.append("image", data)
axios.post('http://localhost:3000', formData)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input required ref={register} type="file" name="image" />
<button>Submit</button>
</form>
)
}
Typescript is identifying a problem with the declaration of FileUploadForm on line 5, giving me the error I specified in the title. Although, I'm uncertain if it's to do with Typescript. I'm also getting the following compiler error:
My project structure is as follows:
My package.json is as follows:
{
"name": "file-uploader-frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^5.11.4",
"#testing-library/react": "^11.1.0",
"#testing-library/user-event": "^12.1.10",
"#types/axios": "^0.14.0",
"axios": "^0.21.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-hook-form": "^7.13.0",
"react-scripts": "4.0.3",
"typescript": "^4.3.5",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"#types/node": "^16.7.2"
}
}
Currently, this is the state of the compiled FileUploadForm.jsx. The component is being imported into App.js as a named import:
"use strict";
exports.__esModule = true;
exports.FileUploadForm = void 0;
var react_1 = require("react");
var react_hook_form_1 = require("react-hook-form");
var axios_1 = require("axios");
var FileUploadForm = function () {
var _a = react_hook_form_1.useForm(), register = _a.register, handleSubmit = _a.handleSubmit;
var onSubmit = function (data) {
console.log(data);
var formData = new FormData();
formData.append("image", data);
axios_1["default"].post('http://localhost:3000', formData);
};
return (<form onSubmit={handleSubmit(onSubmit)}>
<input required ref={register} type="file" name="image"/>
<button>Submit</button>
</form>);
};
exports.FileUploadForm = FileUploadForm;
I'm sure there are several other problems with my code, but I can't even begin to explore them if I can't get past this problem so I can get the page to render. I've attempted this as both a named export and a default export. The result is the same. I'm at a loss for what to do next. Any help would be appreciated.
Seems like the problem is related to the export format of your jsx file.
exports.FileUploadForm = FileUploadForm;
In that case, you need to import it as follow.
import {FileUploadForm} from '...path'
But I would like to say use export default
export default FileUploadForm;
import FileUploadForm from '...path'

Resources