What is a useless Constructor in React? - reactjs

I have two files
Description.js and
subjects.js
Subject.js file contains an array of subjects
export const Subjects=[
{
id:1,
title:"Mathematics",
text:"Cheat Sheet for Mathematics",
img:"./Images/math.jpg",
},
{
id:2,
title:"C-programming",
text:"Cheat Sheet for C-Programming",
img:"./Images/cprog.jpg",
},
{
id:3,
title:"Physics",
text:"Cheat Sheet for Physics",
img:"./Images/physics.jpg",
},
{
id:4,
title:"Youtube",
text:"Recomended Youtube videos for Learning",
img:"./Images/youtube.jpg",
},
]
I want to use this array in Description.js .I'm using a map function
import React, { Component } from 'react';
import {Subjects} from './subjects'
class Description extends Component{
constructor(props){
super(props);
}
render(){
const description =this.props.Subjects.map((subjects)=>{
return(
<h1>{subjects.title}</h1>
)
})
return(
{description}
)
}
}
export default Description;
But I am recieving an error of
TypeError: Cannot read property 'map' of undefined
Also in my vs code terminal.I have these mentioned
Line 2:9: 'Subjects' is defined but never used no-unused-vars
Line 5:5: Useless constructor no-useless-constructor

A "useless constructor" is one that the linter is warning you can safely remove from the code, because it doesn't accomplish anything - if all you have is a super call (with the same argument the class is created with), the constructor doesn't do anything useful, because classes will already call super automatically, if the constructor isn't given:
class Parent {
constructor(name) {
console.log('parent constructor running', name);
}
}
class Child extends Parent {}
const c = new Child('bob');
So, the linter is telling you to delete the following lines:
constructor(props){
super(props);
}
Since the Subjects identifier isn't being used anywhere, it can be removed too. Delete the line:
import {Subjects} from './subjects'

#CertainPerformance answers what a useless constructor is well: basically an ESLint rule that doesn't allow you to have constructors that do nothing.
This should work for what you want to happen, though if this is the extent of the component I would place it in a functional component. In order to use this Subject array as a prop you'd have to import it in another component and pass to Description like <Description subjects={Subjects} />
import React, { Component } from 'react';
import { Subjects } from './subjects';
class Description extends Component {
render() {
const description = Subjects.map(subjects => {
return <h1>{subjects.title}</h1>;
});
return <div>{description}</div>;
}
}
export default Description;
Or as a functional component:
import React from 'react';
import { Subjects } from './subjects';
const Description = () => {
const description = Subjects.map(subjects => {
return <h1>{subjects.title}</h1>;
});
return <div>{description}</div>;
};
export default Description;

Related

Can I create instances of components with "new" keyword and use that in render() method?

Note: working solution below
I am wondering if I can simply create new instances of React components in "code" using the "new" keyword, vs creating elements as pseudo-html (if that is the correct name). I'd like to know how to do this and if it's even possible? I am using the class syntax.
EG: var comp1 = new MyComponent({ title: "test 1" });
VS: <MyComponent title="test1" />
Example code:
//MyComponent
import { Component } from "react";
export class MyComponent extends Component<any, {title: string}> {
render() {
return <div>{this.props.title}</div>
}
}
//App
import { Component, ReactElement, ReactNode } from "react";
import { MyComponent } from "./mycomponent";
import "./styles.css";
export default class App extends Component {
renderComponents = () => {
// THIS IS WHAT I WANT, BUT DOES NOT WORK
// var nodes: MyComponent[] = [];
// var comp1 = new MyComponent({ title: "test 1" });
// var comp2 = new MyComponent({ title: "test 2" });
// nodes.push(comp1);
// nodes.push(comp2);
//This works
var nodes:ReactElement[] = [];
nodes.push(<MyComponent title="test1" />);
nodes.push(<MyComponent title="test2" />);
return nodes;
};
render() {
return <div className="App">{this.renderComponents()}</div>;
}
}
Update:
Please note: I am fairly new to React and Typescript and did not write javascript in like 10 years.
The reason why I want to create instances of components using the "new" keyword is partly because I am familiar doing it like that and because I (think) that code will be cleaner that way, especially when combining/chaining more elements together. Personal preference...
I also am still learning about components, elements and such. I am not exactly sure why I can't return an array of MyComponent and why ReactElement (or ReactNode) works instead.
Update2:
Thank you all for your feedback. I am just curious about how things work and experimenting, and I need to RTFM (I did, but I am doing other work in between and forgot some basics).
Working code, for those who might have the same question:
//mycomponent.tsx
import React from "react";
import { Component } from "react";
export class MyComponent extends Component<any, { title: string }> {
render() {
return <div>{this.props.title}</div>;
}
}
//App.tsx
import React from "react";
import { Component, ReactElement } from "react";
import { MyComponent } from "./mycomponent";
export default class App extends Component {
renderElements = () => {
var elements: ReactElement[] = [];
var element1 = React.createElement(MyComponent, { title: "Test1" }, null);
var element2 = React.createElement(MyComponent, { title: "Test2" }, null);
elements.push(element1);
elements.push(element2);
return elements;
};
render() {
return <div className="App">{this.renderElements()}</div>;
}
}
No, creating a new component instance is not the same as using JSX. Also, you would need to account for components being functions and not just classes.
JSX is syntactic sugar for calling React.createElement(MyComponent, props). So by not using JSX you are keeping React out of the process of creating and managing the component. This means no state, re-rendering, etc, and just won't work as needed.
You could use this verbose syntax yourself instead of JSX, but theses are your only two options.

React TS: Despite passing method through wrapper, child still can't access getPage()

I'm trying to build a fetch method that can be shared to a bunch of Reader components through a higher order component. I believe I've built the HOC right, but I'm not 100% sure.
import React, { Component } from 'react';
import base from "./firebase";
export default (ChildComponent) => {
class GetPage extends Component<{},any> {
constructor(props: any) {
super(props);
this.state = {
text: "Hii"
};
}
public getPage(page: string) {
base
.fetch(page, { context: this, })
.then(data => this.setState({ text: data }));
console.log(this.state.text)
}
public render() {
return <ChildComponent getPage={this.getPage} text={...this.state.text} {...this.props}/>;
}
}
return GetPage;
};
You can see that I'm importing the HOC on the second line , but despite this, the 'Reader' component is throwing an error that 'getPage' is no where to be found.
import * as React from "react";
import GetPage from "./fetch";
class Reader extends React.Component<{},any>{
public componentWillMount() {
this.getPage('1A1');
}
public render() {
return <div{...getPage('1A1')}>{...this.state.text}</div>;
}
}
export default (GetPage(Reader));
Inside your Reader component instead of accessing this.getpage try with this.props.getpage
and I don't understand why you are doing with following:
<div{...getPage('1A1')}>

How to include the Match object into a ReactJs component class?

I am trying to use my url as a parameter by passing the Match object into my react component class. However it is not working! What am I doing wrong here?
When I create my component as a JavaScript function it all works fine, but when I try to create my component as a JavaScript class it doesn't work.
Perhaps I am doing something wrong? How do I pass the Match object in to my class component and then use that to set my component's state?
My code:
import React, { Component } from 'react';
import axios from 'axios';
import PropTypes from 'prop-types';
class InstructorProfile extends Component {
constructor(props, {match}) {
super(props, {match});
this.state = {
instructors: [],
instructorID : match.params.instructorID
};
}
componentDidMount(){
axios.get(`/instructors`)
.then(response => {
this.setState({
instructors: response.data
});
})
.catch(error => {
console.log('Error fetching and parsing data', error);
});
}
render(){
return (
<div className="instructor-grid">
<div className="instructor-wrapper">
hi
</div>
</div>
);
}
}
export default InstructorProfile;
React-Router's Route component passes the match object to the component it wraps by default, via props. Try replacing your constructor method with the following:
constructor(props) {
super(props);
this.state = {
instructors: [],
instructorID : props.match.params.instructorID
};
}
Hope this helps.
Your constructor only receives the props object, you have to put match in it...
constructor(props) {
super(props);
let match = props.match;//← here
this.state = {
instructors: [],
instructorID : match.params.instructorID
};
}
you then have to pass that match object via props int a parent component :
// in parent component...
render(){
let match = ...;//however you get your match object upper in the hierarchy
return <InstructorProfile match={match} /*and any other thing you need to pass it*/ />;
}
for me this was not wrapping the component:
export default (withRouter(InstructorProfile))
you need to import withRouter:
import { withRouter } from 'react-router';
and then you can access match params via props:
someFunc = () => {
const { match, someOtherFunc } = this.props;
const { params } = match;
someOtherFunc(params.paramName1, params.paramName2);
};
Using match inside a component class
As stated in the react router documentation. Use this.props.match in a component class. Use ({match}) in a regular function.
Use Case:
import React, {Component} from 'react';
import {Link, Route} from 'react-router-dom';
import DogsComponent from "./DogsComponent";
export default class Pets extends Component{
render(){
return (
<div>
<Link to={this.props.match.url+"/dogs"}>Dogs</Link>
<Route path={this.props.match.path+"/dogs"} component={DogsComponent} />
</div>
)
}
}
or using render
<Route path={this.props.match.path+"/dogs"} render={()=>{
<p>You just clicked dog</p>
}} />
It just worked for me after days of research. Hope this helps.
In a functional component match gets passed in as part of props like so:
export default function MyFunc(props) {
//some code for your component here...
}
In a class component it's already passed in; you just need to refer to it like this:
`export default class YourClass extends Component {
render() {
const {match} = this.props;
console.log(match);
///other component code
}
}`

Can't find an internal method in a React container component

I'm trying to get AJAX-retrieved data into a parent React component so it can be fed down to a child component. I'm using the popular pattern for this defined here where a comment list is used as the example:
components/CommentList.js
import React from 'React';
export class CommentList extends React.Component {
constructor(props) {
super(props);
}
render() {
return <ul> {this.props.comments.map(renderComment)} </ul>;
}
renderComment({body, author}) {
return <li>{body}—{author}</li>;
}
}
components/CommentListContainer.js
import React from 'React';
import { CommentList } from './CommentList';
export class CommentListContainer extends React.Component {
constructor() {
super();
this.state = { comments: [] }
}
componentDidMount() {
$.ajax({
url: "http://get/some/api",
dataType: 'json',
success: function(comments) {
this.setState({comments: comments});
}.bind(this)
});
}
render() {
return <CommentList comments={this.state.comments} />;
}
}
index.js: the entry point for webpack
import React from 'react'
import { render } from 'react-dom'
import { CommentListContainer } from './components/CommentListContainer';
window.React = React;
render(
<CommentListContainer />,
document.getElementById('nav__react-target')
)
When doing all this, I get the following error:
Uncaught ReferenceError: renderComment is not defined
I've move the methods around as well as tweaked the importing of dependencies in various spots with no luck. Any ideas?
Thanks in advance.
You don't have unguarded references to sibling methods with ES2015 classes (as you do in Java / C#, etc.) - instead you need to explicitly reference this to get at the methods of the class:
render() {
// I changed map(renderComment) to map(this.renderComment)
return <ul>{this.props.comments.map(this.renderComment)}</ul>;
}

Click event in ReactJS error: imports/ui/ParentComponent.jsx:5:16: Unexpected token (5:16)

I am trying to learn Event in ReactJS.
I created 2 components
ChildComponent is
import React, { Component } from 'react';
// App component - represents the whole app
export default class ChildComponent extends Component {
render() {
return (
<button onClick={this.props.onBannerClick}>Click me!</button>
);
}
}
And ParentComponent is
import React, { Component } from 'react';
import ChildComponent from './ChildComponent.jsx'
// App component - represents the whole app
export default class ParentComponent extends Component {
performMagic: function() {
alert('TAADAH!');
},
render() {
return (
<BannerAd onBannerClick={this.performMagic} />
);
}
}
but I got the error
Errors prevented startup:
While building for web.browser:
imports/ui/ParentComponent.jsx:5:16: Unexpected token (5:16)
Your application has errors. Waiting for file change.
I think the error is from
performMagic: function() {
alert('TAADAH!');
},
But I do know what the error is.
By the way, can anybody recommends me good debug tools for ReactJS?
Because you're using the ES6 syntax you'll have to bind the function to the instance using the following approach.
constructor(props) {
super(props)
this.performMagic = this.performMagic.bind(this)
}
This will allow you to use the this keyword in the onClick call
import React, { Component } from 'react';
import ChildComponent from './ChildComponent.jsx'
// App component - represents the whole app
export default class ParentComponent extends Component {
constructor(props) {
super(props)
this.performMagic = this.performMagic.bind(this)
}
performMagic() {
alert('TAADAH!');
}
render() {
return (
<BannerAd onBannerClick={this.performMagic} />
);
}
}
Need to write:
performMagic () {
alert('TAADAH!');
},
You need to use new sintax for functions, when write class which is new sintax.
EDIT: You can use "React Developer Tools" chrome extension and gaearon "redux-devtools" for development.
You need to use the new ES6 syntax when making your React Component a class. Use
performMagic() {
alert('TAADAH!');
}
make sure you don't put a comma after the function

Resources