Accessing a variable from outside a function - Javascript, API, XMLHttpRequest - javascript

Just wanting to access the 'data' variable from this XMLHttpRequest function. Need to use the data in my 'App' react component which is below.
I have tried making the 'let data' global?
But just need to be able to access it outside of the function where the 'outside' console.log is. Currently, it shows undefined.
So asking how to make my data be accessed by my react component 'App'.
Sorry, I am new to using this function to get API data.
Thank you for the help, and if you need any more information please ask!
const request = new XMLHttpRequest()
request.open('GET', 'https://ghibliapi.herokuapp.com/films', true)
let data
request.onload = function () {
let data = JSON.parse(this.response)
if (request.status >= 200 && request.status < 400) {
data.forEach((movie) => {
console.log(movie.title)
})
} else {
console.log('error')
}
}
console.log(data,"outside")
request.send()
class App extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<>
<DateRangePickerWrapper value={this.state.child1}/>
</>
)
}
}

You're using class programming on your react aplication, so you must do somenthing
like this
import axios from 'axios'
class App extends Component {
constructor(props){
super(props);
this.state = {data: []}
}
componentDidMount(){
axios.get("https://ghibliapi.herokuapp.com/films")
.then(response =>{
this.setState({data: response.data});
})
.catch(function(error){
console.log(error)
})
}
componentDidUpdate(){
axios.get("https://ghibliapi.herokuapp.com/films")
.then(response =>{
this.setState({data: response.data});
})
.catch(function(error){
console.log(error)
})
}
render() {
return (
<div>
{data.map(data=> (
//logic to render the api's data
))}
</div>
)
}
}

This is how to do it
import React, { useEffect, useState } from "react";
export default function App() {
const [readData, writeData] = useState();
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => writeData(json));
}, []);
return (
<>
<div>title: {readData.title}</div>
<div>completed: {String(readData.completed)}</div>
</>
);
}
Sandbox
I struggled with this exact question when I was first dealing with async code.
If you have async code in React the formula is simple. Have some state, when the async code runs, update the state and the changes should be reflected in your jsx.

Related

Undefined is Not an Object (evaluating 'this.state.data.confirmed.value')

I am new to React Native and practicing by creating a project which makes requests from a COVID-19 API. However, when I run my code, I get this error:
TypeError: undefined is not an object (evaluating 'this.state.data.confirmed.value')
import React from 'react';
import { View, Text } from 'react-native';
class TrackerScreen extends React.Component {
state = {
data: ''
}
componentDidMount = () => {
fetch('https://covid19.mathdro.id/api', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
data: responseJson
})
})
.catch((error) => {
console.error(error);
});
}
render() {
return (
<View>
<Text>
{this.state.data.confirmed.value}
</Text>
</View>
)
}
}
export default TrackerScreen;
I converted my componentDidMount to an arrow function as suggested by other members on an old thread but that did not get rid of the error. Does anybody have a solution to this issue? Any help would be appreciated. Thank you!
The first render will happen before the componentDidMount will be called. So, during the first render the data property from your state will be an empty string. And the code inside the render function is trying to access a nested prop. Either provide a more described state, like:
state = {
data: { confirmed: { value: null } }
}
or check the value inside the render function:
import React from 'react';
import { View, Text } from 'react-native';
class TrackerScreen extends React.Component {
state = {
data: ''
}
componentDidMount = () => {
fetch('https://covid19.mathdro.id/api', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
data: responseJson
})
})
.catch((error) => {
console.error(error);
});
}
render() {
const { data: {confirmed: { value } = { value: null } } } = this.state
return value ? (
<View>
<Text>
{value}
</Text>
</View>
): null;
}
}
export default TrackerScreen;
You probably don't want to render anything if the data isn't present at the moment, so an additional check for the value will handle that

How do I manipulate data that is located in state and display to page?

I'm making three separate axios calls that each set the state with some data. Where do I do my data manipulation with the state data not to change the state but to display something else where?
For example out of the transactionItems state, I want to get all transactions for the current date. All transaction items have the date set automatically when its added to the database.
I'm having issues parsing the data because my setstate seems to update 3 times with all the axios calls.
There are other data manipulations I would like to be able to do as well but I feel like I'll hit another roadblock.
import React, { Component } from "react";
import axios from "axios";
import moment from "moment";
import TransactionSummary from "./TransactionSummary";
import BudgetSummary from "./BudgetSummary";
import DebtSummary from "./DebtSummary";
class DashboardTable extends Component {
constructor(props) {
super(props);
this.state = {
transactionItems: [],
budgetItems: [],
debtItems: [],
spentToday: ""
};
}
componentDidMount() {
this.getTransactionData();
this.getBudgetData();
this.getDebtData();
}
getTransactionData = () => {
axios.defaults.headers.common["Authorization"] = localStorage.getItem(
"jwtToken"
);
axios
.get("/api/transactions")
.then(res =>
this.setState({
transactionItems: res.data
})
)
.catch(err => console.log(err));
};
getBudgetData = () => {
axios.defaults.headers.common["Authorization"] = localStorage.getItem(
"jwtToken"
);
axios
.get("/api/budgets")
.then(res =>
this.setState({
budgetItems: res.data
})
)
.catch(err => console.log(err));
};
getDebtData = () => {
axios.defaults.headers.common["Authorization"] = localStorage.getItem(
"jwtToken"
);
axios
.get("/api/debts")
.then(res =>
this.setState({
debtItems: res.data
})
)
.catch(err => console.log(err));
};
render() {
return (
<div>
<div className="content">
<TransactionSummary transactionItems={this.state.transactionItems} />
<BudgetSummary budgetItems={this.state.budgetItems} />
<DebtSummary debtItems={this.state.debtItems} />
</div>
</div>
);
}
}
export default DashboardTable;
Here's DebtSummary component
import React from "react";
const DebtSummary = props => {
let sumOfDebtItems = props.debtItems.reduce((a, c) => {
return a + c["balance"];
}, 0);
return (
<div>
<p>Debt Summary</p>
{sumOfDebtItems}
</div>
);
};
export default DebtSummary;
Like Hemadri said, the easiest way to do this is to move the 3 axios calls into their respective component
You can also move the data manipulation into a separate method and call it in the render method. You can write as many of these as you need, they can all read from the same state variable
DebtSummary example:
import React from "react";
class DebtSummary extends React.Component {
constructor(props) {
super(props);
this.state = {
debtItems: []
}
}
getDebtData = () => {
axios.defaults.headers.common["Authorization"] = localStorage.getItem(
"jwtToken"
);
axios
.get("/api/debts")
.then(res =>
this.setState({
debtItems: res.data
})
)
.catch(err => console.log(err));
};
// Do some data manipulation, in the case computing the debt sum
sumOfDebtItems = () => {
return this.state.debtItems.reduce((a, c) => {
return a + c["balance"];
}, 0);
}
// Load the debt data once the component has mounted
componentDidMount() {
this.getDebtData()
}
render() {
return (
<div>
<p>Debt Summary</p>
{this.sumOfDebtItems()}
</div>
);
}
};
export default DebtSummary;

ReactJS TypeError: undefined is not a function (near '...this.state.data.map...')

I am new at React and trying to learn it. I am getting data from API and I will use the data. It returns money rates based on 'USD'. I am gonna use that data for convert money but I am getting this error: Error here
I don't know what the problem is.
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor (props) {
super(props)
this.state = {data: 'false'};
}
componentDidMount(){
this.getData();
}
getData = () => {
fetch("https://openexchangerates.org/api/latest.json?app_id=88a3d2b24b174bf5bec485533a3bca88")
.then(response => {
if (response.ok) {
return response;
} else {
let errorMessage =
'${response.status(${response.statusText})',
error = new Error(errorMessage);
throw(error);
}
})
.then(response => response.json())
.then(json =>{
console.log(json);
this.setState({ data: json.data })
});
}
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">React App</h1>
</header>
{
this.state.data &&
this.state.data.map( (item, key) =>
<div key={key}>
{item}
</div>
)}
</div>
);
}
}
export default App;
Thanks for your time.
Set your initial data property in the state to an empty array [].
A stringified 'false' evaluates to true which is why it tries to call the map function, but string doesn't have a map function.
constructor (props) {
super(props)
this.state = {data: []};
}
Working example here
Because this.state.data is not an array, it's a string.
Just use the below code and remove this.state.data && from render method.
constructor (props) {
super(props)
this.state = {
data: []
};
}

How to reload current page in ReactJS?

How to reload current page in ReactJS? in case of javascript we can write window.location.reload();
How to do the same in Reactjs? I'm able to add new data by UI. But without refreshing, I'm not able to see the list. I want it so that whenever I'm adding some data, it refreshes by itself.
onAddBucket() {
let self = this;
let getToken = localStorage.getItem('myToken');
var apiBaseUrl = "...";
let input = {
"name" : this.state.fields["bucket_name"]
}
axios.defaults.headers.common['Authorization'] = getToken;
axios.post(apiBaseUrl+'...',input)
.then(function (response) {
if(response.data.status == 200){
let result = self.state.buckets.concat(response.data.buckets)
}else{
alert(response.data.message);
}
})
.catch(function (error) {
console.log(error);
});
}
use this might help
window.location.reload();
You can use window.location.reload(); in your componentDidMount() lifecycle method. If you are using react-router, it has a refresh method to do that.
Edit: If you want to do that after a data update, you might be looking to a re-render not a reload and you can do that by using this.setState(). Here is a basic example of it to fire a re-render after data is fetched.
import React from 'react'
const ROOT_URL = 'https://jsonplaceholder.typicode.com';
const url = `${ROOT_URL}/users`;
class MyComponent extends React.Component {
state = {
users: null
}
componentDidMount() {
fetch(url)
.then(response => response.json())
.then(users => this.setState({users: users}));
}
render() {
const {users} = this.state;
if (users) {
return (
<ul>
{users.map(user => <li>{user.name}</li>)}
</ul>
)
} else {
return (<h1>Loading ...</h1>)
}
}
}
export default MyComponent;
Since React eventually boils down to plain old JavaScript, you can really place it anywhere! For instance, you could place it in a `componentDidMount()' function in a React class.
For your edit, you may want to try something like this:
class Component extends React.Component {
constructor(props) {
super(props);
this.onAddBucket = this.onAddBucket.bind(this);
}
componentWillMount() {
this.setState({
buckets: {},
})
}
componentDidMount() {
this.onAddBucket();
}
onAddBucket() {
let self = this;
let getToken = localStorage.getItem('myToken');
var apiBaseUrl = "...";
let input = {
"name" : this.state.fields["bucket_name"]
}
axios.defaults.headers.common['Authorization'] = getToken;
axios.post(apiBaseUrl+'...',input)
.then(function (response) {
if (response.data.status == 200) {
this.setState({
buckets: this.state.buckets.concat(response.data.buckets),
});
} else {
alert(response.data.message);
}
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
{this.state.bucket}
);
}
}
You can use useNavigate and navigate to the same url you are on. For example, instead of window.location.reload(), you can say navigate("/...your current url....")
window.location.reload() is not the best option everytime. It works on localhost, but for example on when you deploy it to the internet by using services such as "Netlify", it can can cause "not found url" error
Creating some extra state and tracking them for re-rendering your page might unnecessarily complicate your code.
And using useEffect() to re-render your page, again, will unnecesarily complicate your code.
This is my code .This works for me
componentDidMount(){
axios.get('http://localhost:5000/supplier').then(
response => {
console.log(response)
this.setState({suppliers:response.data.data})
}
)
.catch(error => {
console.log(error)
})
}
componentDidUpdate(){
this.componentDidMount();
}
window.location.reload(); I think this thing is not good for react js
use useHistory method in react
import {useHistory} from 'react-router-dom'
const history = useHistory()
history.go(0) // it will refresh particullar page
or use useEffect method
const [data, setData] = useState([])
useEffect(()=>{
setData(reponseApidata)},[data])
//in useEffect dependcy you mention particullar state for you store reposnse data

React.js - Loading single post data from API correctly

I am fairly new to React, and trying to work my way through how I should properly be loading data from my API for a single post.
I have read that I should be using "componentDidMount" to make my GET request to the API, but the request is not finished by the time the component renders. So my code below does not work, as I am recieving the error: "Cannot read property setState of undefined".
What I am doing wrong here? Should I be calling setState from somewhere else? My simple component is below - thanks.
import React from 'react';
import Header from './Header';
import axios from 'axios';
class SingleListing extends React.Component {
constructor(props) {
super(props);
this.state = {
listingData: {}
}
}
componentDidMount() {
// Get ID from URL
var URLsegments = this.props.location.pathname.slice(1).split('/');
// Load the listing data
axios.get('/api/listing/' + URLsegments[1])
.then(function(res){
let listingDataObject = res.data;
console.log(listingDataObject);
this.setState({
listingData: listingDataObject
});
})
.catch(function(err){
console.log(err);
});
}
render() {
console.log('helsdfdsfsdflssosso');
console.log(this.state.listingData);
return (
<div className="SingleListing">
<Header />
<div className="container">
<div>Property Address: {this.state.listingData.propertyAddress}</div>
This is a single listing
</div>
</div>
)
}
}
export default SingleListing;
You just need to change what you render depending on whether the data is loaded or not yet.
Also, you should use arrow functions when handling the axios response, otherwise this is not set correctly.
class SingleListing extends React.Component {
constructor(props) {
super(props);
this.state = {
listingData: null,
};
}
componentDidMount() {
// Get ID from URL
const URLsegments = this.props.location.pathname.slice(1).split('/');
// Load the listing data
axios
.get(`/api/listing/${URLsegments[1]}`)
.then(res => {
const listingDataObject = res.data;
console.log(listingDataObject);
this.setState({
listingData: listingDataObject,
});
})
.catch(err => {
console.log(err);
});
}
render() {
const isDataLoaded = this.state.listingData;
if (!isDataLoaded) {
return <div>Loading...</div>;
}
return (
<div className="SingleListing">
<Header />
<div className="container">
<div>Property Address: {this.state.listingData.propertyAddress}</div>
This is a single listing
</div>
</div>
);
}
}
export default SingleListing;
this is out of scope you need to include it. here is a solution using es2015 arrow functions =>
axios.get('/api/listing/' + URLsegments[1])
.then((res) => {
let listingDataObject = res.data;
console.log(listingDataObject);
this.setState({
listingData: listingDataObject
});
})
.catch((err) => {
console.log(err);
});

Categories

Resources