Why declearing function(Element) outside render doesn't work? - reactjs

I want to create a dynamic Element inside parent Component class. It gives Unexpected token at function declaration. However writing same function inside return(..here..) works. What am I missing?
This is my code:
import React, { Component } from 'react';
import '../App.css';
var axios = require('axios');
class DisplayRevenue extends Component {
constructor(props){
super(props);
this.state = { data:[] }
}
componentWillMount() {
this.loadRevenue(this.props.url, this.props.token);
}
setData(data){
this.setState(data:data);
console.log(this.state.data); //this gives output as json object
}
loadRevenue(url,token){
axios({
method:'get',
url:url,
headers: {
Authorization: `Bearer ${token}`,
},
})
.then( (response) => {
// console.log(response.data);
this.setData(response.data);
})
.catch(function (error) {
console.log("Error in loading Revenue "+error);
});
}
var ListData = this.state.data.map( (invoice) => {return <div>{invoice.customerNumber}</div>})
//above function gives error
render() {
//var listData = this.state.data.map( (invoice) => (<div>{invoice.customerNumber}</div>)
return (
<div>
<h3>MonthToDate</h3>
{this.state.data.map((invoice) => {return <div>{invoice.customerNumber}</div>})}
</div>
);
}
}
export default DisplayRevenue;
I have json object array as below:
"data": [
{
"customerId": 0,
"customerNumber": "IT8SDS",
"customerType": "RVN",
"invoiceType": "LBR",
"invoiceAmt": "52651.2287",
"invoiceStatus": "BILLED",
"invoiceDate": "2016-12-30T00:00:00.000Z"
},
{
"customerId": 1,
"customerNumber": "DC0WTY",
"customerType": "RVN",
"invoiceType": "RNT",
"invoiceAmt": "198503.1828",
"invoiceStatus": "BILLED",
"invoiceDate": "2016-12-30T00:00:00.000Z"
},
{
"customerId": 2,
"customerNumber": "LK8MD5",
"customerType": "INT",
"invoiceType": "EQT",
"invoiceAmt": "-6833.70721",
"invoiceStatus": "PENDING",
"invoiceDate": "2016-12-30T00:00:00.000Z"
},
{
"customerId": 3,
"customerNumber": "E03PTJ",
"customerType": "PCT",
"invoiceType": "PTS",
"invoiceAmt": "55670.17911",
"invoiceStatus": "BILLED",
"invoiceDate": "2016-12-19T00:00:00.000Z"
},
NOTE: Writing {this.state.data.map((invoice) => {return <div>{invoice.customerNumber}</div>})} inside return(..here..) in render() works.

You can't declare variables inside a class body.
You can do that inside functions (such as render, constructor, react life cycle methods, custom functions etc...).
If you want to do it the "react way" make ListData as a component:
Example:
const ListData = data => (
<div>
{data.map( (invoice) => <div>{invoice.customerNumber}</div>)}
</div>
);
And use it like so:
render() {
return (
<div>
<h3>MonthToDate</h3>
<ListData data={this.state.data} />
</div>
);
}
Here is a working example:
const ListData = ({data}) => (
<div>
{data.map((o) => (<div>{o}</div>))}
</div>
);
const App = () => (
<div>
<h2>Hello</h2>
<ListData data={["Hi", "i'm", "a", "test"]} />
</div>
);
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Related

REACT GET requiest getting base url twice

Using REACT front-end with Django back-end. When i call request api i can see it being pulled correctly, however when onClick is called i get a 404 XHRGEThttp://localhost:3000/http//127.0.0.1:8000/undefined so it seems that i am somehow calling the base url twice but i am not sure how?
here is my main component file:
import React, { Component } from 'react';
import SubtagsList from './list_subtags';
import axios from 'axios';
class TagsList extends Component {
constructor(props) {
super(props);
this.state = {
tagData: [],
subtags: " ",
showComponent: false,
}
this.getSubtagDetail = this.getSubtagDetail.bind(this);
this.showSubtags = this.showSubtags.bind(this);
}
getSubtagDetail(item){
axios.get("http//127.0.0.1:8000/".concat(item.absolute_url))
.then((response) =>{
this.setState({subtags: response.data})
})
.catch(function(error){
console.log(error);
})
}
showSubtags(item){
this.getSubtagDetail(item);
this.setState({showComponent: true})
}
componentDidMount(){
axios.get("http://127.0.0.1:8000/")
.then( (response) => {
this.setState({tagData: response.data})
})
.catch(function(error) {
console.log(error);
})
}
render() {
return (
<div>
{this.state.tagData.map((item) => {
return (
<h3 key={item.id} onClick={() => this.showSubtags(item)}>
{item.tag_name}
</h3>
);
})}
{this.state.showComponent ? (
<SubtagsList subtagDetail={this.state.subtags} />
) : null}
</div>
)
}
}
export default TagsList;
here is the api response:
[
{
"id": 2,
"tag_name": "IT/Computer Issues",
"type": "Tag"
},
{
"id": 1,
"subtag_name": "Website",
"absolute_url": "/1",
"type": "SubTag"
}
]
and this is the SubtagsList component imported:
import React, { Component } from 'react';
class SubtagsList extends Component {
render() {
const obj = this.props.subtagDetail;
return (
<div style={{ color: "yellow", border: "1px solid yellow" }}>
<p>{obj.subtag_name}</p>
</div>
)
}
}
export default SubtagsList;
Can anyone shed some light on what i might be doing wrong here?

display data based on pass value id

i want to display data based on its id. i have 2 page, app.js and display.js. in app.js i already display a table and clickable data to link to display.js. but i cant display data n display.js based on its id. i use API to get this all data and data in display.js is looping all data on result json and not only by id that i click on app.js.
can anyone helpme to pass the id from app.js to display.js and not loop data on display.js?
here's my code
App.js
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
errors: null,
isLoading: true
};
}
getData = async () => {
const option = {
url:api/url
method: 'POST',
headers: {
"Access-Control-Allow-Origin": "*"
},
data: {
"data": {
"data": "111111"
},
"encrypt": 0
}
};
axios(option)
.then(response => {
const tableData = response.data.data.map(post => {
const {id, name, type} = post;
return [
<Link to={'/display'}>{id}</Link>, //when i click this it link to display.js and in display.js only display data based on this id
<Link to={'/display'}>{name}</Link>,
<Link to={'/display'}>{type}</Link>
];
});
this.setState({
data: tableData,
isLoading: false
});
})
);
}
componentDidMount() {
this.getData();
}
render() {
const columns = ["ID", "Name", "Type"];
const options = {
filterType: "dropdown",
responsive: "scroll",
selectableRows:false
};
return (
<div>
<center><h3>Table</h3></center><br/>
{!isLoading ? (
<MUIDataTable
data={this.state.data}
columns={columns}
options={options}
/>)
: (
<p>Loading...</p>
)}
</div>
);
}
}
export default App
display.js
class App extends React.Component {
// State will apply to the posts object which is set to loading by default
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: true,
errors: null
};
}
// Now we're going to make a request for data using axios
getData = async () => {
const option = {
url:api/url
method: 'POST',
headers: {
"Access-Control-Allow-Origin": "*"
},
data: {
"data": {
"data": "111111"
},
"encrypt": 0
}
};
axios(option)
.then(response => {
this.setState({
data: response.data.data,
isLoading: false,
});
console.log(response.data);
const data = JSON.parse(data);
})
);
}
componentDidMount() {
this.getData();
}
// Putting that data to use
render() {
const { isLoading, data} = this.state;
return (
<React.Fragment>
<h3>Data display</h3><br/>
<div>
{!isLoading ? (
data.map(post => {
const {id, name, age, type, gender} = post;
return (
//from API this data is looping and more than 1, i want to after click id from app.js it will link to this display.js page and only show data based on id
<div>
<Card>
<CardHeader color="info">
<h4 >Data </h4>
</CardHeader>
<CardBody>
<div><b>ID</b></div>
<div>{id}</div>
<div><b>Name</b>
<div>{name}</div>
<div><b>age</b></div>
<div>{age}</div>
<div><b>type</b></div>
<div >{type}</div>
<div><b>gender</b></div>
<div>{gender}</div>
</CardBody>
</Card>
<br/>
</div>
);
})
) : (
<p>Loading...</p>
)}
</div>
</React.Fragment>
);
}
}
export default App;
anyone can help to only show page display.js based on id i click in app.js?
You can pass the id within of the clicked row within the link child
<Link to={{
pathname: '/display',
state: {
data: post
}
}}></Link>
and in your display component you can get the id to send with the request
const { data } = this.props.location.data
and in your display component you'll get all the clicked row data and you can remove the loop from the render as well as the request

How to pass data to props from state?

I'm learning React and have some troubles with using state and props. There is two files: App.js and component. In App.js i use axios to get JSON data from IP and store in a state. But I cannot pass the data to props through the state.
Here is App.js:
import React from 'react';
import axios from 'axios';
import Shutruk from './Shutruk';
const qwerty = {
"data": [
{
"_id": "5d1cb18e4af03042df6267c5",
"title": "Shutruk",
"description": "Shhhhhhhhhhhhh",
"date": "2019-07-03T13:45:50.850Z",
"__v": 0
},
{
"_id": "5d1cc27b37c9751001f5c12f",
"title": "Shilkhak",
"description": "Shilkhak-Inshushinak",
"date": "2019-07-03T14:58:03.797Z",
"__v": 0
},
{
"_id": "5d1cc45655780f11112a023f",
"title": "Унташ",
"description": "Untash-Napirisha",
"date": "2019-07-03T15:05:58.699Z",
"__v": 0
},
{
"_id": "5d1ef36c503601183b5f856f",
"title": "dgfdgfdhgf",
"description": "bbbbbbbbbbbbbbbbb",
"date": "2019-07-05T06:51:24.873Z",
"__v": 0
},
{
"_id": "5d1ef381503601183b5f8570",
"title": "qewytuytruytru",
"description": "jhfgasjdfgasjdfgjhsdf",
"date": "2019-07-05T06:51:45.761Z",
"__v": 0
}
]
};
class App extends React.Component {
state = {
data: []
}
componentDidMount() {
axios.get('http://localhost:5555/posts')
.then(res => {
const data = res.data;
this.setState({ data });
})
}
render() {
return (
<div>
<Shutruk name={ this.state.data.data[0].title }/>
</div>
)
}
}
export default App;
Here is the component:
import React from 'react';
class Shutruk extends React.Component {
render() {
return (
<div>
<h1>This is is {this.props.name}!</h1>
</div>
)
}
}
export default Shutruk;
I use axios to get data from backend, but when I insert it to props, it does'nt work. I create an array qwerty[] with the same data, and when I replace with:
return (
<div>
<Shutruk name={ qwerty.data[0].title }/>
</div>
)
it works correctly. What is the problem, if there is no difference between 'this.state.data' and 'qwerty'?
I checked with console.log and the result is same!
Thanks to everyone for any help!
This is because, axios and setState are asynchronous and when the component loads in componentDidMount, it takes a while to load data into state and since data.data[0] is still empty, it doesn't work. But when you use a const to declare it, it works as it is already present.
Instead of
<Shutruk name={ this.state.data.data[0].title }/>
Do:
renderShutruk = () => {
if (this.state.data.data !== undefined) {
return <Shutruk name={this.state.data.data[0].title} />
} else {
return null;
}
};
render() {
return (
<div>
{this.renderShutruk()}
</div>
);
}
Your App component is probably crashing when mounting while you're accessing an undefined state because your try to get this.state.data.data[0].title when data state equals []
Try replacing your App component like this to prevent access to an undefined state (I recommend doing this for all your asynchronous operations in the components):
class App extends React.Component {
state = {
data: [],
loading: true,
error: false,
}
componentDidMount() {
axios.get('http://localhost:5555/posts')
.then(res => {
const data = res.data.data; // get the data array instead of object
this.setState({ data, loading: false });
})
.catch(err => { // log request error and prevent access to undefined state
this.setState({ loading: false, error: true });
console.error(err);
}
render() {
if (this.state.loading) {
return(
<div>
<p> Loading... </p>
</div>
)
}
if (this.state.error || !this.state.data[0]) { // if request failed or data is empty don't try to access it either
return(
<div>
<p> An error occurred </p>
</div>
)
}
return (
<div>
<Shutruk name={ this.state.data[0].title }/> // access to data array state
</div>
)
}
}
export default App;
Just change this,
<Shutruk name={ this.state.data.data[0].title }/>
with,
{this.state.data ? <Shutruk name={ this.state.data[0].title }/> : null}
Update
If you are not getting data, then you must use async/await,
async componentDidMount() {
await axios.get('http://localhost:5555/posts')
.then(res => {
//console.log(res) => if `res` is {data:[...]} , then do this,
const data = res.data;
//console.log(res) => if `res` is {data: data: [...]} , then do this,
const data = res.data.data;
this.setState({ data });
})
}

How to get an item from an array in JSON in ReactJS?

I am trying to get an item "icon" from "weather" form following JSON
{
"coord": {
"lon": 14.33,
"lat": 49.94
},
"weather": [{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}]
}
I can't figure out how to exctract an item which is in array through render method.
My code is:
class Weather extends React.Component {
constructor() {
super();
this.state = {
'items': []
}
}
componentDidMount() {
this.getItems();
}
getItems() {
fetch('http://api.openweathermap.org/data/2.5/weather?lat=49.9415967&lon=14.3316786&appid=ed62e370682cc9e4144620905eff37e4')
.then(results => results.json())
.then(results => this.setState ({'items': results}));
}
render() {
return (
<div>
<h1>here should be an icon..</h1>
{this.state.items.weather.map(function(weather, index) {
return <h3 key={index}>{weather.icon}</h3>
})}
</div>
);
}
}
I actually used this question here: Get access to array in JSON by ReactJS ...which got me this far, but still can't make it working...
Your weather array is not set until your fetch request is complete, so this.state.items.weather.map in your render method will result in an error.
You could give weather an empty array as default value.
class Weather extends React.Component {
constructor() {
super();
this.state = {
items: {
weather: []
}
};
}
componentDidMount() {
this.getItems();
}
getItems() {
fetch(
"http://api.openweathermap.org/data/2.5/weather?lat=49.9415967&lon=14.3316786&appid=ed62e370682cc9e4144620905eff37e4"
)
.then(results => results.json())
.then(results => this.setState({ items: results }));
}
render() {
return (
<div>
<h1>here should be an icon..</h1>
{this.state.items.weather.map(function(weather, index) {
return <h3 key={index}>{weather.icon}</h3>;
})}
</div>
);
}
}
copy paste this example in codesandbox.io .you were initializing the items in constructor as array(where as fetch gave you an object) and for the initial render, items.weather was undefined and in render method you were trying to access map of undefined which was causing the error. (I have changed the url to https to run it in codesandbox)
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
constructor() {
super();
this.state = {
items: {}
};
}
componentDidMount() {
this.getItems();
}
getItems() {
fetch(
"https://api.openweathermap.org/data/2.5/weather?lat=49.9415967&lon=14.3316786&appid=ed62e370682cc9e4144620905eff37e4"
)
.then(results => results.json())
.then(results => this.setState({ items: results }));
}
render() {
return (
<div>
<h1>here should be an icon..</h1>
{this.state.items.weather &&
this.state.items.weather.map(function(weather, index) {
return <h3 key={index}>{weather.icon}</h3>;
})}
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

React: Iterate over object, find array, and display array items

I'm trying to iterate over an object being return by the axios call to "/Home/NewsNotes".
Response from Axios
I'm able to display the property names to the screen, but I'm having issues accessing the "NewsNotes" array.
Here's my code for my component.
class ReleaseDetailsComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
releaseNotes: {}
};
}
componentDidMount() {
var _this = this;
const urlParams = new URLSearchParams(window.location.search);
const currCatId = urlParams.get('categoryId');
axios.get('/Home/NewsNotes?categoryId=' + currCatId)
.then(response => _this.setState(
{ releaseNotes: response.data }
))
.catch(function (error) {
console.log(error);
});
console.log(currCatId);
}
render() {
return (
<section>
<div className="row">
<div className="col-sm-8 col-sm-offset-2 col-md-10 col-md-offset-1">
<h2 className="page-title tutorials"><img className="title-icon" src="/Content/images/icons/icon-release-notes.png" /> News & Release Notes</h2>
<h3>{this.state.releaseNotes.Title}</h3>
{Object.keys(this.state.releaseNotes).map(function (item, key) {
return (
<p>{item}</p>
);
})}
</div>
</div>
</section>
);
}
}
ReactDOM.render(
<ReleaseDetailsComponent />,
document.getElementById('tutorialsWrapper')
);
I assume the object which you retrieved from URL using axios will look like:
var releaseNotes = {
NewsNotes: [
"Buy some milk": "data 1",
"Clean kitchen": "data 2",
"Watch Netflix": "data 3"
],
NewsNotesCategoryId: 3,
SortOrder: null,
Title: "1.0.1",
TypeId: 2
};
Next, you can inject "this" into map method as follow, check for any child array, then push each JSX block into the temp array in order to return later:
{Object.keys(this.state.releaseNotes).map((key, idx) => {
var temp = [];
temp.push(<p>{key}</p>);
if (Array.isArray(this.state.releaseNotes[key])) {
this.state.releaseNotes[key].map(ckey => {
temp.push(<p>{ckey}</p>);
});
}
return temp;
}, this)}
You can't render an array of elements using keys. Rather map over the array and print them like this.
renderReleaseNotes() {
return _.map(this.state.releaseNotes, releaseNote => {
return (
<p>releaseNote.title</p>
);
});
}
Hope this helps. Happy coding !

Resources