React functional (hooks) component in parent class component - javascript

I have a quite big React component SearchProvider written as a class and a UI component InputRange that I wrote as functional component using Hooks.
ATM I am getting the error "Invalid hook call. Hooks can only be called inside of the body of a function component."
Can I use the hook component as a child of the class component?
import { InputRange } from 'react-components';
class SearchProvider extends Component {
render() {
return <Fragment>
<InputRange />
{this.props.children}
</Fragment>;
}
function InputRange(props) {
...
useEffect(_ => { ...});
return <div className="input-range"></div>;
}

I answer my own question. The problem was duplicated react and not directly related to hooks. See https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react
I had to declare react and react-dom in the UI component as peerDependencies. This solves the problem.

Related

React Functional Component: how to use componentDidMount() [duplicate]

This question already has answers here:
componentDidMount equivalent on a React function/Hooks component?
(11 answers)
Closed 3 months ago.
I have a function which is technically a React Functional Component:
export default function Daw() {
return (
<>
<div>Hello world.</div>
</>
);
}
Of course, my ordinary function cannot have the ReactJS method of componentDidMount(). Since it is not a class which extends React.PureComponent.
I'm using this function inside a ReactJS web app.
export default function Daw() {
componentDidMount() { // ** Cannot use this ReactJS method!?
}
return (
<>
<div>Hello world.</div>
</>
);
}
Question
How can I possibly call componentDidMount() method of ReactJS inside my ordinary function? Is there a way to do it, without converting my function to a class which extends React.PureComponent? Is it possible?
First import useEffect from react
import { useEffect } from "react";
Then use useEffect with an empty dependency array,it is same as componentDidMount()
useEffect(() => { console.log("Mounted"); },[]);
Refer react official documentation for learning all lifecycle methods using useEffect hook:- https://reactjs.org/docs/hooks-effect.html
You're going to need React Hooks! All life-cycle methods we were doing in class components are available in functional components too via React Hooks, even in a better way. Read more about React hooks here: https://reactjs.org/docs/hooks-intro.html
And in this case, the equivalent of componentDidMount is this:
import { useEffect } from 'react'
export default function Daw() {
useEffect(() => {
// Code here will run just like componentDidMount
}, [])
return (
<>
<div>Hello world.</div>
</>
)
}
You can also learn about Effects in React by reading my article: A Beginner’s Guide to Effects in React
You cannot use componentDidMount() (class lifecycle methods) in React functional components. Instead you can use useEffect hook to perform the same operation. Like this:
useEffect(() => {
}, []);
Check here for more info - Similar Question
yes, you can use useEffect hook.
useEffect has the following abilities of class methods .i.e. componentDidMount, componentDidUpdate and componentWillUnmoun.
refer following info from official doc:
https://reactjs.org/docs/hooks-effect.html

React adding FloatingMenuButton Package Parsing error: Unexpected token

I am new to React and trying to add the Floating Menu Button from this Package.
Adding this I get following Error.
Parsing error: Unexpected token
I have uploaded the Code.
https://codesandbox.io/s/adding-floatingmenu-2tfxe?file=/src/App.js
I also have another Question. What is the difference of adding render() {} infront of return() or just leaving return()?
Update
I have Updated my Code inside codesandbox, there i do not receive an Error, after I copied it into VSCode i receive following error.
You can use react hooks only in functional components. If you use class components you not allowed to use hooks.
But what is a Hook?
Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks don’t work inside classes — they let you use React without classes.
Second question the same situation, render() uses in class components, in functional components you just use return(<></>)
Please read hooks owerview:
https://reactjs.org/docs/hooks-overview.html
If you want to initialize the isOpen state as false, here's a minimal example of that
import React, { Component } from "react";
import {
FloatingMenu,
MainButton,
ChildButton,
} from "react-floating-button-menu";
export default class Login extends Component {
constructor(props) {
super(props)
this.state = {
isOpen: false
}
}
render() {
return (
<FloatingMenu
slideSpeed={500}
direction="up"
spacing={8}
isOpen={this.state.isOpen}
>
<MainButton
backgroundColor="black"
onClick={() => this.setState({ open: !this.state.isOpen })}
size={56}
/>
</FloatingMenu>
);
}
};
Make sure you import Component from 'react' at the top. Render method is required when you're making a React component using a class method which you are using. It's a type of lifecycle method which is invoked when the component needs to update. The return statement only returns the data/JSX elements wherever it is being used.
If you are using functional components, you don't need a render method since they return the react elements themselves

Pass React Props to a Separate JS File

I'm trying to pass props for width from a parent component to a child JS file, but cannot seem to get the props value in the child JS file. The parent is the following:
import React from 'react';
import Child from './Child';
export default class Home extends React.Component {
state = {
width: 1000
}
render(){
return(
<div>
<Child width={this.width} />
</div>
);
}
}
The separate child JS file is the following:
import React from 'react';
const svgWidth = 650, // Load prop here
svgHeight = 340;
What I've tried is the following but is not working for me:
import React from 'react';
const Child = (props) => {
console.log({props.width}); // Getting an error that ',' is expected
return {props.width};
}
Can someone please help me with passing the width value from ?
Change to the following, as you should access state through this.state, like so:
<Child width={this.state.width} />
Either use the prop drilling, hence pass the values from parent to child as a prop.
But exact answer to your question will be :
create a blank object in separate js file and export it and then in componentDidMount populate that object with the props which you want to save. Next time when ever you will use that object anywhere in normal js file you will get the props.
If you intend to pass props to a child component, then I would start with the following:
import React from 'react';
import Child from './Child';
export default class Home extends React.Component {
constructor(props) { // don't forget to add a constructor
super(props); // also required
this.state = {
width: 1000
}
}
render(){
// to pass state use {this.state}
return(
<div>
<Child width={this.state.width} />
</div>
);
}
}
However, if that is not the case and instead you want to export state to a separate js file (that may not even be a React component), then you may have to look at export syntax. I am struggling with a similar problem right now and I already tried what Vikash Kumar suggested without success. This is explained on this question but I was not successful with that approach either: export function inside react component or access state in same file outside of component

How to test component that contains a component connected to Redux in Enzyme / React?

There's a familiar gotcha when testing React components that are connected to Redux in Enzyme. You may have run into this error:
Invariant Violation: Could not find "store" in either the context or props of "Connect(YourComponent)
This is resolved by exporting the component under test twice:
export class YourComponent extends Component {}
export default connect(mapStateToProps, mapDispatchToProps)(YourComponent);
And in your test import YourComponent as an object:
import { YourComponent } from '../pathToYourComponent'
I've run into a novel scenario regarding this issue.
I'm testing a connected component, and I'm using the solution above to resolve that issue, however inside that component there is another connected component that gets rendered when certain props are present.
import React, { Component } from 'react';
export class YourComponent extends Component {
constructor(props) {
super(props)
}
render() {
const { arrayOfObjects } = this.props;
let nestedConnectedComponent;
if (arrayOfObjects.length) {
nestedConnectedComponent = arrayOfObjects.map((ele, idx) => (
<NestedConnectedComponent
key={idx}
/>
))
}
return (
<div> {arrayOfObjects} </div>
)
}
}
function mapStateToProps(){}
function mapDispatchToProps(){}
export default connect(mapStateToProps, mapDispatchToProps)(YourComponent);
How do you avoid the "could not find store" error when you are testing a component that contains a component that is connected to redux?
The component is being shallow rendered in the latest version of Enzyme.
You won't get this error if you use shallow rendering, from docs
'Shallow rendering is useful to constrain yourself to testing a component as a unit, and to ensure that your tests aren't indirectly asserting on behavior of child components.'

Testing functional components with renderIntoDocument

I am learning to test React stateless components using the ReactTestUtils library. This is my simple component:
import React from 'react';
const Greeter = ({name,place}) => (
<h1>Hello,{name}. Welcome to the {place}.</h1>
);
export default Greeter;
This is my test spec, to get the renderIntoDocument working, I wrapped my Greeter component in a div as suggested here:
import {expect} from 'chai';
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';
import Greeter from '../Greeter';
describe('Greeter Components',() => {
it('renders correctly',() => {
var component = ReactTestUtils.renderIntoDocument(<div>
<Greeter name="Vamsi" place="Hotel California"/>
</div>);
var hasH1 = ReactTestUtils.findRenderedDOMComponentWithTag(component,'h1');
expect(hasH1).to.be.ok;
});
});
I get the error
findAllInRenderedTree(...): instance must be a composite component.
I am providing my code as jsbin here.
Since function components don't have an instance associated with them, you can't use them directly with render or renderIntoDocument. Attempting to wrap the function component is a good idea, unfortunately using a div doesn't work for a similar reason. DOM components also don't return a component instance, instead they return the underlying DOM node.
Which is all to say that you can't use the test utils function or native components as the "root" component you are rendering. Instead you will want to wrap your function components in a wrapper component that uses createClass or extends React.Component.
class Wrapper extends React.Component {
render() {
return this.props.children
}
}
let component = renderIntoDocument(<Wrapper><Greeter /></wrapper>
Gotcha's like this may be reason enough to make use of a third-party testing library like the popular enzyme, or my own take: teaspoon. Both abstract over issues like this by seamlessly wrapping and unwrapping function components for you, so you don't need to worry about what type of component you are trying to render.
Wrapping functional components in a <div> works for me. You just have to search for the component you want to test a little differently, i.e.
const props = { p1: "1" }
test('Foo renders correctly classed div', () => {
const cpt = TestUtils.renderIntoDocument(<div><Foo {...props} /></div>);
const myNode = ReactDOM.findDOMNode(cpt.childNodes[0]);
expect(myNode.className).toBe('my-class');
});
notice that you can target myNode for testing using cpt.childNodes[0]
In order to improve #monastic-panic's answer, my two cents:
You don't have to create a class for that. Do it dynamically:
import createReactClass from 'create-react-class';
// need to be a class component
const Clazz = createReactClass({
render: () => {
return <YourFunctionalComponentName {...props} />;
},
});
ReactTestUtils.renderIntoDocument(<Clazz />);

Categories