"'this' is a reserved keyword" in React app, why? [duplicate] - reactjs

I'm stuck on a error for the reserved keyword "this". In my React Component below shows me passing in a state from a my main component "App.js" to my "RecipeList.js" component to then map the data and render each RecipeItem Component. I just don't understand why I get this error
React.js - Syntax error: this is a reserved word
The error is called in RecipeList inside the render return method; If anybody could help that would great!
Thanks
App.js
//main imports
import React, { Component } from 'react';
//helper imports
import {Button} from 'reactstrap'
import RecipeItem from './components/RecipeItem';
import RecipeList from './components/RecipeList';
import './App.css';
const recipes = [
{
recipeName: 'Hamburger',
ingrediants: 'ground meat, seasoning'
},
{
recipeName: 'Crab Legs',
ingrediants: 'crab, Ole Bay seasoning,'
}
];
class App extends Component {
constructor(props){
super(props);
this.state = {
recipes
};
}
render() {
return (
<div className="App">
<div className = "container-fluid">
<h2>Recipe Box</h2>
<div>
<RecipeList recipes = {this.state.recipes}/>
</div>
</div>
<div className = "AddRecipe">
<Button>Add Recipe</Button>
</div>
</div>
);
}
}
export default App;
RecipeLists.js
import React, {Component} from 'react';
import _ from 'lodash';
import RecipeItem from './RecipeItem';
class RecipeList extends Component {
renderRecipeItems() {
return _.map(this.props.recipes, recipeItem => <RecipeItem key = {i} {...recipes} />);
}
render() {
return (
{ this.renderRecipeItems() }
);
}
}
export default RecipeList

All the solutions given here are correct.
The easiest change is to just wrap your function call in a JSX element:
return (
<div>
{ this.renderRecipeItems() }
</div>
)
However, none of the answers are (correctly) telling you why the code was breaking in the first place.
For the sake of an easier example, let's simplify your code a bit
// let's simplify this
return (
{ this.renderRecipeItems() }
)
such that the meaning and behavior are still the same. (remove parenths and move curlies):
// into this
return {
this.renderRecipeItems()
};
What this code does is it contains a block, denoted by {}, within which you're trying to invoke a function.
Because of the return statement, the block {} is treated like an object literal
An object literal is a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({}).
which expects either a: b or a (shorthand) syntax for it's property-value pairs.
// valid object
return {
prop: 5
}
// also valid object
const prop = 5;
return {
prop
}
However, you're passing a function call instead, which is invalid.
return {
this.renderRecipeItems() // There's no property:value pair here
}
When going through this code, the engine assumes it will read an object-literal. When it reaches the this., it notices that . is not a valid character for a property name (unless you were wrapping it in a string - see bellow) and the execution breaks here.
function test() {
return {
this.whatever()
// ^ this is invalid object-literal syntax
}
}
test();
For demonstration, if you wrapped your function call in quotes, code would accept the . as part of a property name and would break now because a property value is not provided:
function test() {
return {
'this.whatever()' // <-- missing the value so the `}` bellow is an unexpected token
}
}
test();
If you remove the return statement, the code wouldn't break because that would then just be a function call within a block:
function test() {
/* return */ {
console.log('this is valid')
}
}
test();
Now, an additional issue is that it's not the JS engine that is compiling your code but it's babel, which is why you get the this is a reserved word error instead of Uncaught SyntaxError: Unexpected token ..
The reason is that JSX doesn't accept reserved words from the JavaScript language such as class and this. If you remove this, you can see that the reasoning above still applies - babel tries to parse the code as an object literal that has a property, but no value, meaning babel sees this:
return {
'renderRecipeItems()' // <-- notice the quotes. Babel throws the unexpected token error
}

Wrap the this.renderRecipeItems() part with a div, it will work.
Reason why it was failing, is explained extremely well by #nem035 in this answer.
Like this:
render () {
return (
<div>
{ this.renderRecipeItems() }
</div>
);
}
And i think instead of:
<RecipeItem key = {i} {...recipes} />
It should be:
<RecipeItem key = {i} {...recipeItem} />
These are the changes i can see, may be some others will be required also.

You can avoid this by rewriting RecipeLists.js as a pure stateless component.
As Pure component:
import _ from 'lodash';
import RecipeItem from './RecipeItem';
const RecipeList = props => renderRecipeItems(props);
const renderRecipeItems = ({ recipes }) => _.map(recipes, recipeItem => <RecipeItem key = {i} {...recipes} />);
export default RecipeList;
So now you're component is basically just a function with params.

Related

Reactjs IF statement

I have a component I call that is a passed a recordID and returns the text associated to the Id. 33 should = Tower
will render "Tower" on the screen. All good, but...
When I try to use the component in the following IF statement it does not work.
...
if (<GetAssetTypeNameComponent datafromparent = {assettype_assettypeId}/> === "Tower")
{
this.props.history.push(`/add-assetstower/${assetsid}/${this.props.match.params.sitemasterid}`);
}
Using the passed parameter does work if I change the code to:
...
if (assettype_assettypeId === "33")
{
this.props.history.push(`/add-assetstower/${assetsid}/${this.props.match.params.sitemasterid}`);
}
...
What am I doing wrong?
Rob
Component Code that needs to be a Function....
...
class GetAssetTypeNameComponent extends Component {
constructor (props){
super(props)
this.state = {
assettype:[]
}
}
componentDidMount()
{
AssetTypeService.getAssetTypeById(this.props.datafromparent).then( (res) =>{
let assettype = res.data;
this.setState({isLoading:false});
this.setState({
assettypeName: assettype.assettypeName,
assettypeType: assettype.assettypeType
});
});
}
render() {
return (
<div>
{this.state.assettypeName}
</div>
);
}
}
export default GetAssetTypeNameComponent;
...
Following Function code compiles:
...
import React, { useState} from 'react';
import AssetTypeService from './AssetTypeService'
const GetAssetTypeNameFunction = (props) =>{
// destructuring
const { assettype_assettypeId } = props;
const [assetType,setAssetType] = useState()
AssetTypeService.getAssetTypeById(assettype_assettypeId).then( (res) =>
setAssetType(res.data));
const arrayMap = assetType.map((post)=>{
return(
<ul>
{post.assettypeName}
</ul>
);})
return (
{arrayMap}
);
}
export default GetAssetTypeNameFunction;
...
Get execution error:
I think because I calling the function from within an eventHandler:
...
editAssets(assetsid,assettype_assettypeId){ if (GetAssetTypeNameFunction(assettype_assettypeId) === "Tower") { this.props.history.push(/add-assetstower/${assetsid}/${this.props.match.params.sitemasterid}); }]
...
----- Error: Invalid hook call. Hooks can only be called inside of the body of a function component. I am responding to a onClick in a list to route to a specific component based on the function $
How do I get around this?
A component renders content to be displayed in the page. The retuned value of rendering a component is a tree of nodes that contain your content. All this means that <GetAssetTypeNameComponent> may contain the text content Tower, but it is not equal to the string "Tower". It just doesn't make any sense to render a component as the test for a conditional like this.
In React you want to use logic to tell react how to render. You do not want to render and then use the result in your logic.
It's hard to give advice on the best way to fix that with so little code, but maybe you want a a simple function to coverts the id into some text for you.
function getAssetName(id) {
return someLogicSomewhere(id).result.orWhatever
}
And now you can do something like:
if (getAssetName(assettype_assettypeId) === 'Tower')
{
this.props.history.push(
`/add-assetstower/${assetsid}/${this.props.match.params.sitemasterid}`
);
}

Expected an assignment or function call and instead saw an expression error in react if return is not present inside map statement why?

import React, { Component } from 'react'
export default class DisplayTodo extends Component {
state = {
todo:["eat", "sleep", "repet"]
}
render() {
return (
<div>
{
this.state.todo.map((value)=>{
<p>{value}</p>
})
}
</div>
)
}
}
1) I know if i keep return in map it works but i want know why it failed
2)Moreover i referd to the link in for React
https://reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx
Now the error looks quit opposite to the explanition saying Expected an assignment or function call and instead saw an expression
3)in the react link explanation in above it is said You can put any valid JavaScript expression inside the curly braces
4) Moreover in javascript we can write like this why it is not possible in React
var a = [11,33,99]
a.map((val)=>{
console.log(val*2)
})
So in your code
export default class DisplayTodo extends Component {
state = {
todo:["eat", "sleep", "repet"]
}
render() {
return (
<div>
{ <-- outer expression start
this.state.todo.map((value)=>{
<p>{value}</p> <-- inner expression
})
} <-- outer expression end
</div>
)
}
}
You've got one outer expression, which wraps your JS code, it's completely correct. Your inner expression is also fine, because you use curly braces for JS code inside of JSX element. But, in order for React to render values from todo array, you must return each element from map callback, like that:
export default class DisplayTodo extends Component {
state = {
todo:["eat", "sleep", "repet"]
}
render() {
return (
<div>
{
this.state.todo.map((value)=>{
return <p key={value}>{value}</p>
})
}
</div>
)
}
}
Or you can do:
{
this.state.todo.map(value => <p key={value}>{value}</p>)
}
Note: I also added React keys to each todo in array, so you have some sort of uniqueness(good explanation about React keys)
Hope it helps :)
The curly braces "{}" require a return statement. If you do not want to add a return statement simply use "()" or nothing instead. ex)
this.state.todo.map((value)=>
<p>{value}</p>
)

Results are not populating after fetching from API using React

I am working with some examples to fetch the data from an API using fetch. But, it is returning nothing in view. What i am doing wrong? Why it is not populating? Here is a link to the code.
Application code here:
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import axios from 'axios';
import './style.css';
const url='https://10degrees.uk/wp-json/wp/v2/posts';
class App extends Component {
constructor() {
super();
this.state = {
name: 'React',
searchInput: 'tirur',
avatarDatas: []
};
this.fetchData = this.fetchData.bind(this);
}
componentDidMount(){
this.fetchData(url);
}
fetchData = (apiToFetch)=>{
fetch(apiToFetch)
.then(result=>result.json())
.then(avatarData=>{
this.setState({
avatarDatas : avatarData
})
})
.catch((error) => console.log(error));
}
render() {
console.log(this.state.avatarDatas)
return (
<div>
<Hello name={this.state.name} />
<p>
{this.state.avatarDatas.map(item=>{
<div>{item}</div>
})}
</p>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Your code is fetching data from the remote URL correctly. However, you're using the map function in your render method wrong. You have:
{this.state.avatarDatas.map(item=>{
<div>{item}</div>
})}
This does indeed map through all the entries in avatarDatas, but the function the callback you've provided the map isn't returning anything. You've written a function block with a JSX statement in it, and no return statement. What you should have written is:
{this.state.avatarDatas.map(item=>{
return (<div>{item}</div>);
})}
or even this, where there isn't an actual function block but just a return value:
{this.state.avatarDatas.map(item=>
<div>{item}</div>
)}
At this point, the avatarDatas still won't be listed, because the JSX in your map callback is trying to have item rendered. item is an object, and React won't know how to convert it to a string. Rather do this:
{this.state.avatarDatas.map(item=>
<div>{item.title.rendered}</div>
)}
(Or any other of the many fields that each avatarData has.)
Finally, React may still issue a warning, saying that each item in a list must have a unique key. Whenever you use map to create a number of elements, React expects you to give a unique identifier to each element, which it will use to identify that element when it needs to update your list during rerendering. That means that you should do this:
{this.state.avatarDatas.map((item, index) =>
<div key={index}>{item.title.rendered}</div>
)}
Now, your map callback assigns an index to each <div> and all is well with the world.

Conditional rendering question with ReactJS

I'm trying to use a <Conditional if={condition}> component in React, that renders its content only if the condition is true.
I've used the code from here, as mentioned in Broda Noel's response of this question. You also see the code here.
import * as React from 'react';
const Conditional = props => (
!!props.if && props.children
);
class Item extends React.Component {
render() {
const item = { id: 2 };
return (
<>
<h2>Item detail</h2>
{/* Display item.foo.name if `foo` property exists */}
<Conditional if={item.foo}>
{item.foo.name}
</Conditional>
</>);
}
}
export default Item;
It fails with the error:
Uncaught TypeError: Cannot read property 'name' of undefined
I know I can also use {item.foo && item.foo.name}, but when the code becomes more complex, I find the use of Conditional more readable. And most important, I would really like to understand what happens here.
Why does React render the content of the Conditional, even is the condition is false?
Is there a way to change the Conditional component to make it work in this case?
I'm using React 16.4.1, with typescript.
The code:
<Conditional if={item.foo}>
{item.foo.name}
</Conditional>
is transpiled to:
React.createElement(Condition, { if: item.foo }, item.foo.name)
So even if the condition is false it will try to access the property name.
I suggest that you use the code below when the code becomes more complex:
import * as React from 'react';
class Item extends React.Component {
renderConditional (item) {
if (!item.foo) {
return null;
}
return item.foo.name; // Or some jsx
}
render() {
const item = { id: 2 };
return (
<>
<h2>Item detail</h2>
{this.renderConditional(item)}
</>
);
}
}
export default Item;
You could also create another component to present the data and check the object inside the new component.
The problem is that your component <Conditional> have no logical expression in the if prop. The "React way" to do this is using conditional rendering as is:
render() {
const item = { id: 2 };
return (
<>
<h2>Item detail</h2>
{ item.foo !== undefined && // React Way to Conditional Rendering
{item.foo.name}
}
</>
);
}
I recommend you to read the docs for Conditional Rendering

Referencing object sent to a function in React component

In the following component, if I try to access the properties of myData object inside the getMessage() function, using myData.gender I'm getting an undefined error.
If I try myData.myData.gender it works. Why is that?
When I inspect myData coming into the getMessage() function, I see that it's an object and it contains a myData object in it. I'm confused why myData object is placed inside of another object.
Interestingly, inside my component I can access the properties directly as you can see in the line <div>Hello {myData.firstName}</div>
Here's my simple React component:
import React, {Component} from 'react';
const MyComponent = ({myData}) => {
return(
<div>Hello {myData.firstName}</div>
<div>
{getMessage(myData)}
</div>
);
};
const getMessage(myData) => {
let output = "";
if(myData.Gender == "m") {
output = "<span>Enjoy the football game tonight!</span>";
}
else {
output = "<span>Enjoy your roses!</span>";
}
return output;
}
ChannelContent.propTypes = {
myData: PropTypes.object.isRequired
};
export default MyComponent;
you've a typo either in your question or in code:
try myData.gender === 'm' instead of myData.Gender == "m"

Resources