I am trying to figure out how to respond to the warning in react to use javascript classes to create components in my MERN app.
The warning says:
Warning: Accessing createClass via the main React package is deprecated, and will be removed in React v16.0. Use a plain JavaScript class instead. If you're not yet ready to migrate, create-react-class v15.* is available on npm as a temporary, drop-in replacement. For more info see[ \[this link\][1]
The link in that message says:
// After (15.5)
var React = require('react');
var createReactClass = require('create-react-class');
var Component = createReactClass({
mixins: [MixinA],
render() {
return <Child />;
}
});
I am using react v 15.5.4
In my app, I have tried to change my components as follows:
import React from 'react';
import ReactDOM from 'react-dom';
import { Button } from 'react-bootstrap';
var createReactClass = require('create-react-class');
var GreeterForm = createReactClass({
onFormSubmit: function(e) {
e.preventDefault();
However, the warning persists. Can anyone see what I have done wrong? How do I implement the new approach to defining components?
You should use ES6 class for make a React component.
import React from 'react';
class App extends from React.Component{
constructor(props){
super(props);
this.sample = this.sample.bind(this);
// initialize your methods, states here
}
// if you want life cycle methods and methods define here
componentWillMount(nextProps, nextState){
console.log('componentWillMount');
}
sample(){
console.log('sample');
}
render(){
return <div onClick={this.sample}>Hello World!</div>
}
}
This is what I would do to create a class in React:
import React, { Component } from 'react';
class GreeterForm extends Component {
onFormSubmit = (e) => {
e.preventDefault();
//do stuff
}
render() {
return (<Child onFormSubmit={this.onFormSubmit} />)
}
}
Related
I need to access and test a method of a child component in react using Jest. I am not using Enzyme, so this is not a duplicate of this question or this question. I would like to use React Testing Library instead of Enzyme.
Earlier I was happily accessing the methods I needed to test like this:
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import App from "./App";
let container: any = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
test("methodToTest should do what I want it to", () => {
const { methodToTest } = render(<App />, container);
methodToTest("some input");
const output = document.querySelector(".outputFromMethod");
expect(output.innerHTML).toBe("You gave me some input");
});
But now I need to wrap my <App /> component in withRouter() from react-router-dom, so I have to do something like this: (Based on the recipe suggested by React Testing Library)
import React from "react";
import { BrowserRouter as Router } from "react-router-dom";
import { render, unmountComponentAtNode } from "react-dom";
import App from "./App";
let container: any = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
test("methodToTest should do what I want it to", () => {
// THIS DOESN'T WORK NOW FOR GETTING methodToTest
const { methodToTest } = render(<Router><App /></Router>, container);
const output = document.querySelector(".outputFromMethod");
expect(output.innerHTML).toBe("You gave me some input");
});
I understand that it's not ideal to try to test methods on a child component. But I need to do this because I have to have this component render inside of a <Router>. Is there any way to access the <App /> components methods without using Enzyme, or using React Testing Library if necessary?
You can't do that with Testing Library, that's against the principles. You're also using a strange style for testing. Have you tried to do this:
import React from "react";
import { BrowserRouter as Router } from "react-router-dom";
import { render } from "#testing-library/react";
import App from "./App";
import "#testing-library/jest-dom/extend-expect";
test("methodToTest should do what I want it to", () => {
const { getByText } = render(<Router><App /></Router>);
expect(getByText("You gave me some input")).toBeInTheDocument();
});
I am new to react native, enzyme and jest. I am trying to get a simple test working, to test child nodes. (Perhaps this is an incorrect way of trying to do so).
My Component is:
import React, { Component } from 'react';
import { View, Text, Button, TextInput } from 'react-native';
class MyComponent extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View >
<Button title="My Component"/>
</View>
)
}
}
export default MyComponent;
and my test is
import React from 'react';
import { configure, shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import MyComponent from '../components/MyComponent.js';
configure({ adapter: new Adapter() }) //setting up enzyme
const styles = require('../styles.js');
describe('rendering', () => {
it('checking View and Button exists', () => {
let wrapper
wrapper = shallow(<MyComponent/>);
expect(wrapper.find('View').children().find('Button')).toHaveProperty('title','My Component')
});
})
});
I am getting an error that the object return is not matching the expected:
Expected the object:
< listing of full object...>
To have a nested property:
"title"
With a value of:
"My Component"
The object returned shows MyComponent as a child of the root View, as well as the prop, but it is failing. Should I be doing this differently? I want to be able to create a test structure that will eventually confirm a number of child components and props under the View Component.
(as a side note, I would prefer to use Mocha, but I am coming up against this error which I haven't been able to resolve.
This other question helped me to answer my problem
https://stackoverflow.com/a/46546619/4797507 (apologies if I am not giving credit correctly)
The solution was for me to use:
expect(wrapper.find('View').children().find('Button').get(0).props.title).toEqual('My Component')
I'm building a Modal component based on which I used for ReactJS on the web. I attach the Modal to document.body as a child and mount/unmount as needed.
Here is the diagram (Stephen Grider's Udemy online course)
My problem is there is no ReactDOM or document.body in React Native. Here is my modal.py
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { store } from '../store';
import { Provider } from 'react-redux';
class Modal extends Component {
comoponentDidMount() {
this.modalTarget = document.createElement('div');
this.modalTarget.className = 'modal';
document.body.appendChild(this.modalTarget);
this._render();
}
_render() {
ReactDOM.render(
<Provider store={store}>
<div>{this.props.children}</div>
</Provider>,
this.modalTarget
);
}
componentWillUpdate() {
this._render();
}
componentWillUnmount() {
ReactDOM.unmountComponentAtNode(this.modalTarget);
document.body.removeChild(this.modalTarget);
}
render() {
return <noscript />;
}
}
I'm using Expo and it's loading App.js by default! And there is no document.body and ReactDOM. How can I solve this problem?
We don't have any DOM in react-native. you should create a modal component and import it in other components you want to use. your modal's position must be absolute and for showing modal you can pass a prop to it.
you can use react native modal:
https://facebook.github.io/react-native/docs/modal.html
or any other modals created by people like this :
https://github.com/maxs15/react-native-modalbox
I'm trying to setup a project architecture using MobX and React and was wondering if doing this following would be considered "not bad". I don't want this question to end up being another "this is a matter of personal preference and so this question doesn't belong here... We can all agree that some things really are bad.
So I'm thinking of only having a single Store.js file that looks something like this:
import { observable, action, useStrict } from 'mobx';
useStrict(true);
export const state = observable({
title: ''
});
export const actions = {
setTitle: action((title) => {
state.title = title;
})
};
Note: that all application state will be in state, there will only be a single store.
I then use state in my root component a.k.a App.js like so:
import React, { Component } from 'react';
import { observer } from 'mobx-react';
import { state } from './Store';
import DisplayTitle from './components/DisplayTitle/DisplayTitle';
import SetTitle from './components/SetTitle/SetTitle';
class App extends Component {
render() {
return (
<div className="App">
<DisplayTitle title={state.title}/>
<SetTitle />
</div>
);
}
}
export default observer(App);
I'll obviously have a whole bunch of components in my app, but none of the components will ever read state directly from Store.js. Only my App.js will import the state and pass it down the component tree.
Another note: I'm not so sure anymore why other components can't read the state directly from Store.js...
This is the case with the DisplayTitle component:
import React, { Component } from 'react';
class DisplayTitle extends Component {
render () {
return (
<h1>{this.props.title}</h1>
);
}
}
export default DisplayTitle;
But, even though no other components can directly import state (except App.js), any component can import actions from Store.js in order to mutate the state.
For example in the SetTitle component:
import React, { Component } from 'react';
import { actions } from './../../Store';
class SetTitle extends Component {
updateTitle (e) {
actions.setTitle(e.currentTarget.value);
}
render () {
return (
<input onChange={this.updateTitle} type='text'/>
);
}
}
export default SetTitle;
Are there any flaws or other obvious reasons why this approach wouldn't be the best route to go? I'd love any and all feedback!
you are missing a few things
at root level:
import { Provider } from 'mobx-react'
...
<Provider state={state}>
<Other stuff />
</Provider>
At component level:
import { inject } from 'mobx-react'
#inject('state')
class Foo ... {
handleClick(){
this.props.state.setTitle('foo')
}
render(){
return <div onClick={() => this.handleClick()}>{this.props.state.title}</div>
}
}
You can stick only the interface actions={actions} in your provider and inject that, ensuring children can call your API methods to mutate state and have it flow from bottom up. Though if you were to mutate it direct, no side effects will happen because all components willReact and update in your render tree - flux is cleaner to reason about.
I am a bit new to react and redux, but made quite a lot of progress.
I am using redux connect to map state to props. Was working like charm, until I got this situation:
Parent component is using mapStateToProps, and here is the source code for it:
import React from 'react';
import { connect } from 'react-redux'
import { NestedComponent } from './NestedComponent'
class ParentElement extends React.Component {
render() {
return (
<div className="App">
<NestedComponent/>
</div>
);
}
}
const mapStateToProps = state => {
const { questions } = state
return {
questions
}
}
ParentElement.contextTypes = {
router: React.PropTypes.object.isRequired
}
export default connect(mapStateToProps)(ParentElement)
Here is the code for the nested element:
import React from 'react';
import { connect } from 'react-redux'
class NestedComponent extends React.Component {
render() {
return (
<div> I am nested</div>
);
}
};
const mapStateToProps = state => {
const { questions } = state
return {
questions
}
}
NestedComponent.contextTypes = {
router: React.PropTypes.object.isRequired
}
export default connect(mapStateToProps)(NestedComponent)
When I try to show the parent element, I get this error:
Warning: React.createElement: type should not be null, undefined,
boolean, or number. It should be a string (for DOM elements) or a
ReactClass (for composite components). Check the render method of
ParentElement.
What am I missing / doing wrong?
Import header file like this:-
import NestedComponent from './NestedComponent'
Without braces.
When a class is exported as a default then it is imported without braces because there is only one default class in a file but, when the class is exported without default you have to import it with braces because there can be more than one class with export keywords in a file (es6 conventions).