I'm trying to use the Link component in #fluentui/react, but I get an error about invalid hook calls. I tried using Link in office-ui-fabric-react, but got same hook error.
Background:
Component A calls the code with the Link component.
Component A is in a different folder than Link component.
Error:
"react-dom.development.js:3198 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:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app"
Link code:
import * as React from "react";
import { Link } from "#fluentui/react";
//import { Link } from "office-ui-fabric-react";
export interface ITestProps {
what: string;
click: () => void;
}
export default class TestComponent extends React.PureComponent<ITestProps, {}> {
constructor(props: ITestProps) {
super(props);
}
render() {
return (
<div>
Test {this.props.what}
<button onClick={this.props.click}>Click</button>
<Link onClick={this.props.click}>Click link</Link> <-- this is what is causing hook problems
</div>
);
}
}
Then I tried using a functional component rather than extending from React.PureComponent, but same hook error:
export default function TestComponent(props: ITestProps) {
return (
<div>
Test2 {props.what}
<button onClick={props.click}>Click</button>
<Link onClick={props.click}>Click link</Link> <-- also produces hook error
</div>
);
}
The only way that I solved this problem is my Link code inside the same folder as the Component that uses the Link code.
I want to be able to put my Link code in a separate folder, not in the same folder as Component A.
I also made sure that the react and react-dom version of both folders are the same, but I still got hook errors.
Please any suggestions?
Related
I tried using both bootstrap and react-bootstrap but to no avail. I tried something simple like a button but every time I get a whitescreen and the following error:
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:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
What could be the issue?
CODE:
import React, { Component } from 'react';
import Button from 'react-bootstrap/Button';
export class Home extends Component {
static displayName = Home.name;
state = {
data: []
};
componentDidMount() {
fetch('/api/weeks')
.then(res => res.json())
.then(data => this.setState({ data }))
.catch(error => console.error(error));
}
render () {
const { data } = this.state;
return (
<div>
<h1>Hello, world!</h1>
<Button>Test</Button>
<button>Test</button>
<h2>Weeks Data</h2>
<ul>
{data.map(week => (
<li key={week.id}>{week.name}</li>
))}
</ul>
</div>
);
}
}
EDIT:
I get the following errors, I don't know what i'm supposed to look at:
Uncaught TypeError: Cannot set properties of undefined (setting '_element') at Button (fails.js:7:1)
VM231 react_devtools_backend.js:4012 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:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
The above error occurred in the component
I am following a guide to upgrade to React 18. After completing the upgrade I am seeing errors on certain pages in my app.
ReactDOM.unstable_renderSubtreeIntoContainer() is no longer supported in React 18.
I am not using the unstable_renderSubtreeIntoContainer() function anywhere in my app, but when I look closer at what is causing these errors it seems to be caused my Bootstrap components.
Is there anyway to update this to remove the errors?
I ran into the same problem with react-bootstrap#v0.33.1 specifically when using OverlayTrigger component after upgrading to React 18. The warning message suggests to migrate to using portals. So I implemented a CustomOverlayTrigger component that leverages portals and referred to React's portal documentation to do so. Note that this solution is for Bootstrap 3 usage of OverlayTrigger (react-bootstrap v0.33.1). It seems later versions of react-bootstrap got rid of using ReactDOM.unstable_renderSubtreeIntoContainer. If you are not in a position to migrate to later versions (like I am), this solution will help for this use case. I have not check thoroughly if other components use the deprecated method, but the approach might be the same.
First of all, I copied the original source of the OverlayTrigger component code located here. You will need to clean up the imports and include into your code the utils function createChainedFunction located here.
I then created a portal wrapper based off React's documentation that looks like this:
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
const tooltipRoot = document.getElementById('tooltip-root');
class PortalWrapper extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
}
componentDidMount() {
tooltipRoot.appendChild(this.el);
}
componentWillUnmount() {
tooltipRoot.removeChild(this.el);
}
render() {
// eslint-disable-next-line react/destructuring-assignment
return ReactDOM.createPortal(this.props.children, this.el);
}
}
PortalWrapper.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
};
export default PortalWrapper;
At the top, you can see the line const tooltipRoot = document.getElementById('tooltip-root');, I simply added in my index.html a div next to the react app's root div that will server as the anchor for my portal.
Then, back in the CustomOverlayTrigger component copied from react-bootstrap, I edited it in the follwing manner:
Remove all references to this._overlay and this._mountNode because the PortalWrapper now manages the mounting/unmounting. So I deleted componentDidMount(), componentDidUpdate(), componentWillUnmount() and renderOverlay()
I modified makeOverlay so that its result is wrapped by PortalWrapper so it became the following:
makeOverlay(overlay, props) {
return (
<PortalWrapper>
<Overlay
{...props}
show={this.state.show}
onHide={this.handleHide}
target={this}
>
{overlay}
</Overlay>
</PortalWrapper>
);
}
Finally, I changed the render method's return statement to become:
return (<>
{cloneElement(child, triggerProps)}
{this.makeOverlay(overlay, props)}
</>);
After this, I simply had to replace all my invocations to OverlayTrigger with CustomOverlayTrigger and I had the same result without the warning message.
I have a catalago-component.js which is a web component. I'm trying to use this web component like so:
import React from 'react'
import './../../../assets/catalago-component'
class Loja extends React.Component{
constructor(props){
super(props)
this.state = {}
}
render(){
return(
<React.Fragment>
<div className="page-header">
<h1 className="page-title">Loja</h1>
</div>
<catalago-component></catalago-component>
</React.Fragment>
)
}
}
export default Loja
but every time I run my react app I get this error
src\assets\catalago-component.js
Line 1:1: Expected an assignment or function call and instead saw an expression no-unused-expressions
Line 1:85: Expected an assignment or function call and instead saw an expression no-unused-expressions
Line 1:399: Expected an assignment or function call and instead saw an expression no-unused-expressions
Line 1:599: Expected an assignment or function call and instead saw an expression no-unused-expressions
...
but if I do any changes to the app that makes it recompile then it works just fine
how to solve this error forever? I don't want this app breaking every time I run it for the first time
EDIT: I tried to use this web component with pure html and it worked. take a look
https://eduardopreuss.github.io/web-component/
https://github.com/eduardopreuss/web-component
EDIT 2: link to codesandbox using react + web component https://codesandbox.io/s/hopeful-cohen-ut6mv?file=/src/App.js
I think you might want to try something like this:
import Catalago from './../../../assets/catalago-component'
Then use the component like:
<Catalago></Catalago>
Assuming your Web component issomething like this:
class Catalago extends React.Component {
render() {
return <speical-web-stuff><speical-web-stuff>
}
}
See:https://reactjs.org/docs/web-components.html
As said above, you should give your component a name in order to import.
import Catalago from './../../../assets/catalago-component'
However, sth you may pay attention to.
Below syntax expect your component is written in index.js under the folder catalago-component
import Catalago from './assets/catalago-component' //component locate in file name ```index```
import Catalago from './assets/catalago-component/customizedName.js'
which type of export used in that component
import Catalago from './assets/catalago-component/customizedName.js' // exporting via ```export default``` keyword
import { Catalago } from './assets/catalago-component/customizedName.js' //exporting via ```export``` keyword
Inside your webpack.config.js add this line
Than you can use your component from anywhere inside project.
import Catalago from 'Components'
There is nothing wrong how I imported, it was a eslint error just like #tsecheukfung01 said in the comments. So I added my web component to .eslintignore file and It worked just fine.
more ways to ignore eslint errors here
The way you import your component is perfectly fine.
A web-component is nothing more than any other HTMLElement like a <div> or an <a>, meaning this is NOT a React component and cannot be imported and used as such.
Example web-component
export class MyComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `My Webcomponent!`
}
static get tag() {
return 'my-component';
}
}
customElements.define(MyComponent.tag, MyComponent);
Using the above web-component would look something like:
import './../../../assets/MyComponent.js'
...
render() {
return() {
<div>
<my-component></my-component>
</div>
}
}
import Catalago from './../../../assets/catalago-component'
...
render() {
return() {
<div>
<Catalago //other props/>
</div>
}
}
I am writing a stateless function component in React using WebStorm:
// file1.js
import React from "react";
export default function MyComp({foo}) { return <span>{ foo }</span>; }
Later, I reference the component:
import MyComp from "./file1";
// ... in my other component ...
// I am definitely using the component:
render() { return <MyComp foo="bar"/> }
When performing code analysis, WebStorm complains with the following warning:
Warning:(6, 25) Unused function MyComp
Is this a bug in WebStorm? Do I need to configure WebStorm for React?
Thanks.
I have a redux reducer loaded with several reactjs components.
I want to load these inside other components through this.props
Like: this.props.components.MyReactComponent
class OtherComponent extends Component {
render() {
const Component = this.props.components.MyReactComponent
return (
<div>
<Component />
</div>
)
}
}
Is this possible? If so, how?
EDIT The component is a connected component. I am able to load it but it is broken. In this case, it is a counter, when you click to increment or decrement nothing happens. In the console, there is this error:
Uncaught ReferenceError: _classCallCheck is not defined
if I convert the component into a dumb component (without connecting it), the error is this:
Uncaught ReferenceError: _classCallCheck3 is not defined
EDIT 2
I found out why those errors show up. It is because the react component gets stripped out when stored in the reducer:
A react component would look something like this:
{ function:
{ [Function: Connect]
displayName: 'Connect(Counter)',
WrappedComponent: { [Function: Counter] propTypes: [Object] },
contextTypes: { store: [Object] },
propTypes: { store: [Object] } } }
However, after I store it inside a reducer, it loses its properties and ends up looking something like this:
{ function:
{ [Function: Connect] } }
After reading the comments below, I thought of an alternative. I can store in a reducer the path to each component, then make a new wrapper component that could render those other components from those paths.
I tried it but encoutered a different problem with the funcion require from nodejs that for some weird reason is not letting me user a variable as an argument. For example:
This works:
var SomeContent = require('../extensions/myContent/containers')
This does not:
var testpath = '../extensions/myContent/containers'
var SomeContent = require(testpath)
Giving me the following error:
Uncaught Error: Cannot find module '../extensions/myContent/containers'.
It is adding a period at the end of the path. How can I prevent require to add that period?
If you can think of any other alternative I can implement for what I am trying to do, I would greatly appreciate it.
EDIT 3 Following Thomas advice...
What I am trying to accomplish is this:
I want to be able to render react components inside other react components, I know how to do it the same way most us know how to; however, I want to be able to do it by importing a file that would contain all the components without actually having to import and export each one of them:
OtherComponent.js
import React, { Component } from 'react'
import { SomeComponent } from '../allComponentes/index.js'
export default class OtherComponent extends Component {
render() {
return (
<SomeComponent />
)
}
}
SomeComponent.js
import React, { Component } from 'react'
export default class SomeComponent extends Component {
render() {
return (
<div>
Hello
</div>
)
}
}
allComponents/index.js
import SomeComponent from '../allComponents/SomeComponent/index.js'
export { SomeComponent }
What I am trying to do in allComponents/index.js is to avoid having import/export statements for each component by reading (with fs module) all the components inside the allComponents folder and export them.
allComponents/index.js (pseudocode)
get all folders inside allComponents folder
loop through each folder and require the components
store each component inside an object
export object
When I tried that, I encountered multiple issues, for one, export statements have to be in the top-level, and second, fs would work only on the server side.
So, that is why I thought of loading all the components in a reducer and then pass them as props. But as I found out, they got stripped out when stored them in a reducer.
Then, I thought of only storing the path to those components inside a reducer and have a wrapper component that would use that path to require the needed component. This method almost worked out but the nodejs function require wont allow me to pass a variable as an argument (as shown in EDIT 2)
I think your question is not really to do with redux but rather is (as you say):
What I am trying to do in allComponents/index.js is to avoid having import/export statements for each component by reading (with fs module) all the components inside the allComponents folder and export them.
By way of example, I have all of my (dumb) form components in a folder path components/form-components and the index.js looks something like:
export FieldSet from './FieldSet'
export Input from './Input'
export Label from './Label'
export Submit from './Submit'
export Select from './Select'
export Textarea from './Textarea'
Then when I want to import a component elsewhere, it is import { FieldSet, Label, Input, Submit } from '../../components/form-components/';