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.
Related
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?
I'm new to React testing and with Jest and Enzyme.
I'm trying to learn how to use a TDD approach first and due to that, I'm building my tests before starting coding.
What I did was to create a sample app in React and I installed Enzyme dependencies and then I wrote the test:
import { shallow } from "enzyme";
import React from "react";
import AppLayout from "./AppLayout";
import { ContentLayout } from "./styles";
it("renders <AppLayout /> component", () => {
const wrapper = shallow(<AppLayout />);
expect(wrapper.find(ContentLayout)).to.have.lengthOf(1);
});
Then I built the component which contains a styled component called ContentLayout
import React from "react";
import { ContentLayout } from "./styles";
const AppLayout = () => {
return (
<>
<ContentLayout>
<h1>HELLO</h1>
</ContentLayout>
</>
);
};
export default AppLayout;
I'm unable yo make the test pass as what I got was the next error:
TypeError: Cannot read property 'have' of undefined
I would like to learn how shoulæd be the practice to test this kind of component and what rules to follow in general when I start a project from scratch with TDD in mind.
The AppLayout is called then in App.js
import React from "react";
import AppLayout from "./Components/AppLayout";
function App() {
return <AppLayout />;
}
export default App;
You should use .toHaveLength(number) matchers of expect in jestjs.
expect(wrapper.find(ContentLayout)).toHaveLength(1);
For nested components, there are two strategies generally:
Shallow Rendering API
Shallow rendering is useful to constrain yourself to test a component as a unit, and to ensure that your tests aren't indirectly asserting the behavior of child components.
This means we don't want to render the nested component(ContentLayout), we only test the behavior(lifecycle methods, event handlers, data fetching, condition render, etc.) of the parent component(AppLayout).
Full Rendering API (mount(...))
Full DOM rendering is ideal for use cases where you have components that may interact with DOM APIs or need to test components that are wrapped in higher order components.
I am using react 16.13.1 and created react app using create-react-app 3.4.1.
Mounting lifecycle is being called twice for every component.
I created component FirstComponent.js
import React, {Component} from 'react';
class FirstComponent extends Component {
constructor(p) {
super(p);
console.log("FirstComponent constructor called")
}
componentDidMount() {
console.log("FirstComponent componentDidMount called")
}
static getDerivedStateFromProps() {
console.log("FirstComponent getDerivedStateFromProps called")
return null;
}
render() {
console.log("FirstComponent render called")
return (
<div>
Hello World
</div>
);
}
}
export default FirstComponent;
and called FirstComponent from App.js
import React, {useEffect} from 'react';
import FirstComponent from "./FirstComponent";
function App() {
useEffect(()=>console.log("App useEffect Called"));
console.log("App called");
return (
<FirstComponent/>
);
}
export default App;
console output: (ignoring getDerivedStateFromProps warning)
App called
App called
FirstComponent constructor called
FirstComponent constructor called
FirstComponent getDerivedStateFromProps called
FirstComponent getDerivedStateFromProps called
FirstComponent render called
FirstComponent render called
FirstComponent componentDidMount called
App useEffect Called
This is because codesandbox.io runs react applications in strict mode by using <React.StrictMode /> and in strict mode side effects are double-invoked means executed two times, if you unwrap your <App /> component from <React.StrictMode> in index.js it'll work just fine.
Here's how docs define this:
Strict mode can’t automatically detect side effects for you, but it
can help you spot them by making them a little more deterministic.
This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate methods
Class component static getDerivedStateFromProps method Function
component bodies State updater functions (the first argument to
setState) Functions passed to useState, useMemo, or useReducer
Writing unit testing in react using jest and enzyme. While checking with a component state , it throws an error "ReactWrapper::state() can only be called on class components ".
import React from 'react';
import { mount } from 'enzyme';
import expect from 'expect';
import CustomerAdd from '../CustomerAdd'
import MUITheme from '../../../../Utilities/MUITheme';
import { ThemeProvider } from '#material-ui/styles';
describe('<CustomerAdd />', () => {
const wrapper = mount(
<ThemeProvider theme={MUITheme}>
<CustomerAdd {...mockProps}></CustomerAdd>
</ThemeProvider>
);
test('something', () => {
expect(wrapper.find(CustomerAdd).state('addNewOnSubmit')).toEqual(true);
});
});
In the above code CustomerAdd Component is class component.I don't what wrong with my code. Can any one help me out of this problem. Thanks in advance.
So your default export
export default withStyles(styles)(CustomerAdd);
exports functional(HOC) wrapper about your class-based component. And it does not matter if name of class and import in
import CustomerAdd from '../CustomerAdd'
are equal. Your test imports wrapped version and after calling .find(CustomerAdd) returns that HOC not your class. And you're unable to work with instance.
Short time solution: export class directly as named export.
export class CustomerAdd extends React.Component{
...
}
export default withStyles(styles)(CustomerAdd);
Use named import in your tests:
import { CustomerAdd } from '../CusomerAdd';
Quick'n'dirty solution: use .dive to access your underlying class-based component:
expect(wrapper.find(CustomerAdd).dive().state('addNewOnSubmit')).toEqual(true);
It's rather antipattern since if you add any additional HOC in your default export you will need to monkey-patch all related tests with adding appropriate amount of .dive().dive()....dive() calls.
Long-term solution: avoid testing state, it's implementation details.
Instead focus on validating what's been rendered. Then you are safe in case of lot of different refactoring technics like replacing class with functional component, renaming state/instance members, lifting state up, connecting component to Redux etc.
I'm using the package react-translate to localise my app.
import React from 'react';
import { translate } from 'react-translate';
class Hello extends React.Component {
render() {
return (
<div>
{this.props.t('test_string')}
</div>
);
}
}
export default translate('Hello')(Hello);
In the snippet above, translate is a High Order Component, that adds the function t to the properties of Hello.
Everything works fine but lint keeps complaining because t is not in the propTypes.
error 't' is missing in props validation react/prop-types
Is that normal? I guess I'm doing something wrong but I cannot tell what...
Edit:
As #stevejay says, I could add the t to my propTypes but I don't like this solution because - from my total ignorance in react - 1) t is not a property of the component itself, nor something I want to manually pass and 2) I have to add the property to all the models where I have already added the HOC and it seems redundant
To silence the linter, you need to just add propTypes to your Hello component:
import React from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-translate';
class Hello extends React.Component {
...
}
Hello.propTypes = {
t: PropTypes.func.isRequired
}
Any props that a component you create uses should be declared in that way.