React.js State is not defined in class component - javascript

I am using a class component without a constructor to initialize state. Today, every react app i have tried to create has given me an error
Line 4:3: 'state' is not defined no-undef
my code is
class Page extends Component {
state = {
pages: []
}
render() {
return(
<div>page</div>
);
}
}
export default Page;
the weird part is in my old react apps it works fine. but every new 'npx create-react-app <>' i have tried today all give me undefined unless i use a class constructor.
here are my dependencies
"dependencies": {
"#testing-library/jest-dom": "^5.11.9",
"#testing-library/react": "^11.2.5",
"#testing-library/user-event": "^12.7.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.3",
"web-vitals": "^1.1.0"

Seems there is an issue with React version 16.3.1
I was having this issue today and came to this thread. Finally, after upgrading my npm react version from 16.3.1 to 16.4.0, my code is free of this issue.

Class component should be like this. Reference link of documentation here
class Page extends Component {
constructor(props){
super(props);
this.state = {
pages: []
}
}
render() {
return(
<div>page</div>
);
}
}
export default Page;

import React from 'react'
class Page extends React.Component{
state = {
pages: []
}
render() {
return(
<div>page</div>
);
}
}
export default Page;

Related

No get query sting data in react

I'm trying to get query string parameters tho, it's blank.
This is URL.
https://master.deeiswmgeowge.amplifyapp.com/?site=gfg&subject=react
Then, this.props is empty.
The below is the source.
import React, { Component } from "react";
// Importing Module
import queryString from 'query-string'
class App extends Component {
state = {
site: 'unknown',
subject: 'i dont know'
}
handleQueryString = () => {
// Parsing the query string
// Using parse method
console.log(`this.props`, this.props)
let queries = queryString.parse(this.props.location.search)
console.log(queries)
this.setState(queries)
}
render() {
return (
<div style={{ margin: 200 }}>
<p> WebSite: {this.state.site} </p>
<p> Subject: {this.state.subject} </p>
<button
onClick={this.handleQueryString}
className='btn btn-primary'>
click me
</button>
</div>
);
}
}
export default App;
"dependencies": {
"#testing-library/jest-dom": "^5.11.4",
"#testing-library/react": "^11.1.0",
"#testing-library/user-event": "^12.1.10",
"query-string": "^6.14.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.2",
"web-vitals": "^1.0.1"
},
This is the error image.
You're not using react router , thus no location parameter in props :
so you have two solution ,
1 whether adding react-router-dom and wrap your app with router , ( or using with router hook like export default withRouter(App))
2 or access directly window.location.search and get params with URLSearchParams
by example :
const urlParams = new URLSearchParams(window.location.search);
const site = urlParams.get('site');
const subject = urlParams.get('subject');
Need to pass the props like
onClick={()=> this.handleQueryString(this.props)}
and received like
handleQueryString(arg) {
....
}

React on Web - Uncaught SyntaxError: Cannot use import statement outside a module

On hour four of working this out, I'm really sorry if there's a duplicate but I just looked through all of the suggestions and anything similar, but I need help!
I am reasonably new to React (ReactJS) and wanted to implement an app inside of a webpage.
Everything works great so far for a simple app, but when I am compiling, Babel doesn't compile the "import" line from App.js
The error I get in the browser is
Uncaught SyntaxError: Cannot use import statement outside a module
I think it's because the Babel compiler isn't doing the import, but I am obviously missing some education on this?
Here are the files (I included all that it involves, in case there's something you need to see):
package.json
{
...
"dependencies": {
"babel-cli": "^6.26.0",
"babel-preset-react": "^6.24.1",
"babel-preset-react-app": "^3.1.2"
},
"devDependencies": {
"#babel/preset-env": "^7.8.4"
},
...
}
App.js
'use strict';
import TestComponent from './components/TestComponent';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name : 'Flint',
screen : 'Home'
}
}
handleNameChange = (e) => {
if( this.state.name !== 'Octavia' ){
this.setState({ name: 'Octavia' });
} else {
this.setState({ name: 'Toby' });
}
}
render() {
return (
<div>
<button
className="waves-effect waves-light btn"
onClick={this.handleNameChange}>
{this.state.name}
</button>
</div>
);
}
}
let domContainer = document.querySelector('#App');
ReactDOM.render(<App />, domContainer);
components/TestComponent.js
export default class Header extends React.Component {
render() {
return (
<div>
Test
</div>
)
}
}
And then I run the following...
npx babel --watch src --out-dir dist --presets react-app/prod
And it works perfectly... But I think it just isn't compiling the import correctly in App.js
Thank you for your time!

How to properly add and use third party/npm libraries in Reactjs?

I'm learning react and it's my first time using a library in react. I'm trying to use watermark-js. I've read articles about how I to add npm packages in my react package.json using npm install <library name> save. Here is the part of package.json which show the watermarkjs
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "2.1.8",
"save": "^2.4.0",
"watermarkjs": "^2.0.0"
Now in my App.js component I've imported it as a module and use the snippet provided by watermarkjs in componentDidMount method as in react documentation. below is my complete App.js component.
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Form from './Components/Form';
import ImageWaterMark from './Components/ImageWaterMark';
import image1 from './test-image.jpg'
import image2 from './download.jpg'
import { watermark } from 'watermarkjs'
class App extends Component {
componentDidMount() {
//Snippit
watermark([{ image1 }, { image2 }])
.image(watermark.image.lowerRight(0.5))
.then(function (img) {
document.getElementById('lower-right').appendChild(img);
});
}
render() {
return (
<div className="App">
<div ref="water"></div>
</div>
);
}
}
export default App;
There are 2 problem that I can't seem to understand. first
How can I pass this snippet as a ref to the render method as in
documentation?
Second the App through the following error
TypeError: Cannot read property 'watermark' of undefined
I've read many articles and watched videos but I haven't understand the concept of using libraries. Any help would be much appreciated.
watermarkjs uses a default export, not a named export. Change this:
import { watermark } from 'watermarkjs'`
To this:
import watermark from 'watermarkjs'
As for how to use it, once it loads you should call setState with the result. This will render your component again, and you can use that value however you see fit. For example:
componentDidMount() {
watermark([{ image1 }, { image2 }])
.image(watermark.image.lowerRight(0.5))
.then((img) => {
this.setState({ img });
});
}
render() {
return (
<div className="App">
<div ref="water">
{this.state.img && /* whatever you want to do with the image */ }
</div>
</div>
);
}
I'm not exactly sure what img resolves to, so don't know exactly what you'd put in the render function. If it's url string, it would be {this.state.img && <image src={this.state.img} />}

How to simulate an event on a unit test with Jest, Enzyme for React-Native

I'm trying to figure out how to test an "onPress" event with Jest in a React-Native app so I can make sure the right function is called.
I went through the documentation and Google but couldn't find a solution for it in React-Native.
This is what I found that is supposed to work for React-Native with enzyme:
const mockFunc = jest.fn();
const component = mount(<MyComponent onPress={mockFunc} />);
component.simulate('press');
expect(mockFunc).toHaveBeenCalled();
But this doesn't work. Seems like mount doesn't work and I get this output:
ReferenceError: document is not defined
I tried with shallow instead but the TouchableOpacity is not getting rendered when I look at the output of the function... and you've guessed it, it doesn't work either. Not sure what to do.
Does anyone found a way to test events on React-Native?
Thanks
Enzyme does not support React-Native, because it's rendered differently and doesn't use the DOM. That's why you're getting the error ReferenceError: document is not defined. You can see this issue for more information. The React team is currently working to expose a .find() method in react-test-renderer to simulate actions on components. Then it should work for both React/React-native without needing a DOM environment.
There's a hack you can do (and that's what we did in our company) that is rendering a custom component that extends TouchableOpacity and map onClick to call onPress. Something like this:
const mockPressable = (name) => {
const RealComponent = require.requireActual(name);
class Component extends RealComponent {
render() {
return React.createElement(
RealComponent.displayName || RealComponent.name,
{ ...this.props, onClick: this.props.onPress },
this.props.children
);
}
}
return Component;
};
jest.mock('TouchableOpacity', () => mockPressable('TouchableOpacity'));
And in your test code, you call component.simulate('click').
It's a hack and I'm not sure what are the consequences of doing this but it has worked for our use cases.
You should use shallow instead, then called .dive()
const mockFunc = jest.fn();
const component = shallow(<MyComponent onPress={mockFunc} />);
component.dive().simulate('press');
expect(mockFunc).toHaveBeenCalled();
I'm able to run tests like what you've described in your question in React Native. Here is my configuration:
package.json
"scripts": {
...
"test": "node_modules/jest/bin/jest.js",
}
"devDependencies": {
...
"enzyme": "^3.1.0",
"enzyme-adapter-react-16": "^1.0.1",
"enzyme-to-json": "^3.1.2",
"jest": "^21.2.1",
"jest-enzyme": "^4.0.0",
"jest-expo": "~21.0.0",
}
"jest": {
"preset": "jest-expo",
"setupFiles": [
"./test/jestSetup.js"
],
"snapshotSerializers": [
"./node_modules/enzyme-to-json/serializer"
]
}
test/jestSetup.js
import { configure, shallow, render, mount } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
configure( { adapter: new Adapter() } )
// enzyme
global.shallow = shallow
global.render = render
global.mount = mount
Example component:
import React from 'react'
import { Button } from 'react-native'
const CancelButton = ( props ) =>
<Button
{ ...props }
onPress={ () => { props.navigation.goBack() } }
title="Cancel"
/>
export { CancelButton }
Example test
import React from 'react'
import { CancelButton } from '../CancelButton'
test( 'onPress', () => {
const goBackFunc = jest.fn()
const navigation = {
goBack: goBackFunc,
}
const component = shallow(
<CancelButton
navigation={ navigation }
/>
)
component.simulate( 'press' )
expect( goBackFunc ).toHaveBeenCalled()
} )
.babelrc
{
"presets": ["babel-preset-expo"],
"env": {
"development": {
"plugins": ["transform-react-jsx-source"]
}
}
}

Testing React: Target Container is not a DOM element

I'm attempting to test a React component with Jest/Enzyme while using Webpack.
I have a very simple test #
import React from 'react';
import { shallow } from 'enzyme';
import App from './App';
it('App', () => {
const app = shallow(<App />);
expect(1).toEqual(1);
});
The relative component it's picking up is :
import React, { Component } from 'react';
import { render } from 'react-dom';
// import './styles/normalize.css';
class App extends Component {
render() {
return (
<div>app</div>
);
}
}
render(<App />, document.getElementById('app'));
However, running jest causes a failure:
Invariant Violation: _registerComponent(...): Target container is not a DOM element.
With errors #
at Object.<anonymous> (src/App.js:14:48)
at Object.<anonymous> (src/App.test.js:4:38)
The test files references line 4, which is the import of <App />, that causes a fail. The stack trace says line 14 of App.js is the reason for the failure -- which is nothing more than the render call from react-dom, something I've never had a challenge with (the app renders properly from my Webpack setup).
For those interested (Webpack code):
module.exports = {
entry: './src/App',
output: {
filename: 'bundle.js',
path: './dist'
},
module: {
loaders: [
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015']
}
},
{
test: /\.css$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
},
{
test: /\.scss$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass'
}
]
}
}
And my package.json:
{
"name": "tic-tac-dux",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server --devtool eval --progress --colors --inline --hot --content-base dist/",
"test": "jest"
},
"jest": {
"moduleNameMapper": {
"^.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"^.+\\.(css|sass)$": "<rootDir>/__mocks__/styleMock.js"
}
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.17.0",
"babel-jest": "^16.0.0",
"babel-loader": "^6.2.5",
"babel-polyfill": "^6.16.0",
"babel-preset-es2015": "^6.16.0",
"babel-preset-react": "^6.16.0",
"css-loader": "^0.25.0",
"enzyme": "^2.4.1",
"jest": "^16.0.1",
"jest-cli": "^16.0.1",
"node-sass": "^3.10.1",
"react-addons-test-utils": "^15.3.2",
"react-dom": "^15.3.2",
"sass-loader": "^4.0.2",
"style-loader": "^0.13.1",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.16.2"
},
"dependencies": {
"react": "^15.3.2",
"react-dom": "^15.3.2"
}
}
Oh, and if anyone is going to say that the div element isn't being loaded before the script, here's my index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>App</title>
</head>
<body>
<div id="app"></div>
<script src="/bundle.js"></script>
</body>
</html>
What could be the reason for this peculiar rendering problem? Something to do with a new Jest update to 15.0?
For anyone else that was combing through the internet like I've been - looking for a solution to this when testing with Jest - I will back up the answer by #biphobe by saying Jest will cause this error to occur when you export something inside the same file that is calling ReactDOM.render.
In my case, I was exporting an object within my index.js where I was also calling ReactDOM.render. I removed this export and voila!
App.jsx is supposed to export the App class and do nothing more, render should be called elsewhere.
If you remove the render call from the App.jsx error should disappear, it pops up because the test environment doesn't supply the DOM with an app id.
As I see, this error arises in many cases and requires different approaches to solve it. My scenario is not the same as the example above, I use redux & router, although I was struggling with the same error. What helped me to solve this problem is to change index.js from:
ReactDOM.render(
<Provider store={store}>
<AppRouter />
</Provider>,
document.getElementById("root")
);
registerServiceWorker();
to:
ReactDOM.render(
(<Provider store={store}>
<AppRouter/>
</Provider>),
document.getElementById('root') || document.createElement('div') // for testing purposes
);
registerServiceWorker();
I found a solution for this error to my use case: Using the same Redux store React is using outside of React.
In trying to export my React's Redux store from index.tsx to be used somewhere else outside of the React application, I was getting the same error while running Jest tests (which make use of Enzyme) in the App.tsx file.
The error
The initial code that didn't work when testing React looked like this.
// index.tsx
import * as React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import { applyMiddleware, compose, createStore } from "redux";
import App from "./components/App";
import { rootReducer } from "./store/reducers";
import { initialState } from "./store/state";
const middlewares = [];
export const store = createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middlewares)),
);
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);
The solution that worked for me
Separate the Redux store logic into a new file named store.ts, then create a default export (to be used by index.tsx, i.e., the React application) and a non-default export with export const store (to be used from non-React classes), as follows.
// store.ts
import { applyMiddleware, compose, createStore } from "redux";
import logger from "redux-logger";
import { rootReducer } from "./store/reducers";
import { initialState } from "./store/state";
const middlewares = [];
export const store = createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middlewares)),
);
export default store;
// updated index.tsx
import * as React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import App from "./components/App";
import store from "./store";
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);
Using the Redux store in non-React classes
// MyClass.ts
import { store } from "./store"; // store.ts
export default class MyClass {
handleClick() {
store.dispatch({ ...new SomeAction() });
}
}
The default export
A small note before you go. Here is how to use the default and the non-default exports.
default export store; is used with import store from "./store";
export const store = ... is used with import { store } from "./store";
Hope this helps!
https://nono.ma/says/solved-invariant-violation-target-container-is-not-a-dom-element
Make sure in your test file you have well imported the render component.
It should be imported from #testing-library/react not from react-dom:
import { render } from '#testing-library/react';
Well we cant stop the developers from exporting component from any file and test it in isolation even if it have a react-dom import or usage in it .I mean what's wrong in it . We are not trying to disturb the whole file and test out some pieces of it as long as that is a valid piece of code .
Jest does not have an issue with react-dom , however conceptually they are diff . Jest is supposedly a browserless virtual test environment . React-DOM is a library which does the stitching of virtual DOM to real DOM for react components .
So obvious enough we can/should not test it in a normal way . But that is not the discussion for now. we are fine as long as our exported components are testable .
So Lets mock it
I did the mock in the testSetup file configured with "setupFilesAfterEnv" in jest config .
jest.mock("react-dom", () => {
return ({
"render": jest.fn()
})
})
That is pretty much worked for me. My react and react-dom code now happily go together in one file , works in browser and in the testing environment as well .
I have not encountered any issues because of this . If there is any I will be looking into the comment section
This solution worked for me. Just render if the element is there:
const root = document.getElementById('root');
if (root) {
render(
<App />,
root,
);
}
I found out this error can also be thrown when working with Portals in your tests. If you want to skip the error you can either mock Portals or add the Portal container element in your render method:
render (
<div>
<TestedComponent />
<div id="portal" />
</div>
)

Categories

Resources