I am building a solar system app and I want to have all of my planet's info in a JSON file for easy access. The JSON file is in the following format
Planet-info.json, in the public folder of my React app
"planets": [
{
"Name": "Mercury",
"Description": "The smallest planet in our solar system and closest to the Sun—is only slightly larger than Earth's Moon. Mercury is the fastest planet, zipping around the Sun every 88 Earth days.",
"Moons": 0,
"Habititable": "false"
},
{
"Name": "Venus",
"Description": "is hot",
"Moons": 0,
"Habititable": "false"
}
]
And I am fetching the data with the useEffect hook
const [planetData, setPlanetData] = useState();
useEffect(() => {
const fetchData = () => {
fetch("/planet-info.json").then((result) => {
setPlanetData(result);
});
};
fetchData();
console.log(`planet data is ${planetData}`);
}, []);
However when this code runs and the console.log statement runs it returns the line
planet data is
It does not say undefined, or even [Object object] it is simply blank and I am unable to troubleshoot from there.
fetchData runs asynchronously. So what's happening is
fetchData starts
console.log executes(before the json file has the chance to load)
when the fetch completes, setPlanetData(result) happens.
If you want to see the value printed out, this should do it:
useEffect(() => {
fetch("/planet-info.json").then(result => {
const json = result.json();
console.log(json);
setPlanetData(json);
});
});
Related
I have a json, viewable at https://imgur.com/a/F3kV29F
or here https://dweet.io/get/dweets/for/shyam__5
In python, I am able to print the yearlyWatts by doing:
print(collection[1]['content']['yearlyWatts'])
where collection is the json, done by:
collection = (dweepy.get_dweets_for('shyam__5'))
I am trying to do the same thing in Javascript. Currently, I have done:
getCryptoCurrencyInfo(5)
.then(currencyInfo => {
console.log(currencyInfo[1].yearlyWatts)
This does not work, I get no output.
Please do not pay attention to the function getCryptoCurrencyInfo, I would really appreciate if someone could tell me what to write in the console.log(HERE) in order to output the yearly watts of 111255.51
Any help would be appreciated. Thanks!
Suppose you want a single yearlyWatt.
const data = {
"this": "succeeded",
"by": "getting",
"the": "dweets",
"with": [{
"thing": "shyam__5",
"created": "2020-07-03T08:38:01.184Z",
"content": {
"test": "test"
}
},
{
"thing": "shyam__5",
"created": "2020-07-03T08:37:58.068Z",
"content": {
"yearlyWatts": 111429.4
}
}
]
}
console.log(data.with[1].content.yearlyWatts)
I figured out how to do it thanks to xMayank's help.
In the backend module, the code is:
import { fetch } from 'wix-fetch'
export function getCryptoCurrencyInfo() {
const url = 'https://dweet.io/get/dweets/for/shyam__5'
console.log(url)
return fetch(url, { method: 'get' }).then(response => response.json())
}
To get it to work, the site page (front end) says this:
// For full API documentation, including code examples, visit https://wix.to/94BuAAs
import { getCryptoCurrencyInfo } from 'backend/serviceModule'
import { fetch } from 'wix-fetch'
$w.onReady(function() {
//TODO: write your page related code here...
getCryptoCurrencyInfo().then(currencyInfo => {
const data = currencyInfo
console.log(data.with[1].content.yearlyWatts)
console.log(data.with[2].content.monthlyWatts)
console.log(data.with[3].content.currentDailyCarbonSaved)
console.log(data.with[4].content.currentDailyWatts)
})
})
considering global_obj your json_object, you can do this
global_obj.with.find(element => element.thing==="shyam__5");
I want to define the response structure of my requests in the simplest way, and the first thing that comes in my mind to do this is a middleware.
My endpoints are returning the response content correctly:
{{base_url}}/users returns a list of users:
{
[
{
"id": 44,
"name": "some name"
[...]
}
]
}
What I want to do (in all requests) is to add the fields status and data (or any other I'd like to add), like this:
{
"status": 200,
"data": [
{
"id": 44,
"name": "some name"
[...]
}
]
}
I've created a middleware that waits for the resolution but I'm not able to get the content nor add some property to it.
[...]
async handle ({request, response}, next) {
await next()
const content = response._lazyBody.content
content.status = response.response.statusCode
}
[...]
I know this will not work but I want something similar to this. I've looked in Adonis docs and forum, but no answers fit to my needs.
Any help will be welcome
You can extend Response By extending the core. The simplest way is to create a file inside start folder and name it hooks.js and copy and paste the content below inside it:
const { hooks } = use('#adonisjs/ignitor')
const Response = use('Adonis/Src/Response')
hooks.after.providersBooted(() => {
Response.macro('customJson', function (status, data) {
this.status(status).json({
status,
data
})
})
})
this piece of code extends the Response module and add customJson method to it which takes two arguments, status and data, and send them back to the client.
And here you can see how to use it:
Route.get('/users', async ({ response }) => {
let status = ''// whatever you want
let data = ''// whatever you want
return response.customJson(status, data)
})
I am having a hard time to render a nested object on to a reactjs page
import React, { Component } from "react";
import Toolpanel from "./Todopanel";
import Toollist from "./Toollist";
class App extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
city: "Auckland",
cityWeather: {}
};
this.updateUser = this.updateUser.bind(this);
}
updateUser(entry) {
console.log(entry);
let item = {
text: entry,
key: Date.now()
};
this.setState(prevstate => {
return {
users: prevstate.users.concat(item)
};
});
}
componentDidMount() {
let apiId = "***************************";
let city = this.state.city;
let ApiString =
"http://api.openweathermap.org/data/2.5/weather?q=" +
city +
"&APPID=" +
apiId;
fetch(ApiString)
.then(results => results.json())
.then(data => this.setState({ cityWeather: data }));
}
render() {
let test = this.state.cityWeather;
return (
<div>
<Toolpanel parentUpdate={this.updateUser} />
<div>wind speed : {test.wind.speed} </div>
</div>
);
}
}
export default App;
I have added my JSON file that I received from my weather API
//Json file
{
"coord": { "lon": 174.77, "lat": -36.85 },
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04n"
}
],
"base": "stations",
"main": {
"temp": 293.7,
"pressure": 1018,
"humidity": 77,
"temp_min": 293.15,
"temp_max": 294.26
},
"visibility": 10000,
"wind": { "speed": 5.1, "deg": 360 },
"clouds": { "all": 92 },
"dt": 1553672420,
"sys": {
"type": 1,
"id": 7345,
"message": 0.0043,
"country": "NZ",
"sunrise": 1553624951,
"sunset": 1553667823
},
"id": 2193733,
"name": "Auckland",
"cod": 200
}
I am trying to render the wind speed from the JSON to my page.. but is throwing me a error message saying "TypeError: Cannot read property 'speed' of undefined"...Please help. I am fairly new to ReactJs.
If you look at the code, here is the sequence of events:
Component is created, i.e. constructor is called
Component is mounted, i.e. componentDidMount is called
componentDidMount starts an async request to fetch the data which is then parsed and set in state.
render method tries to read the data from state.
Now, since the request in #3 is an async one, it may not have completed in time when the render method has been called the first time.
So, you need to check if your request has completed or failed or is running.
You can use that to conditionally render the content in your render method.
Recommended reading
The official reactjs blog entry on async rendering with examples of when data is fetched from an external resource
You're not wrong the way you approached it. The error you're getting is because the fetch you're performing is taking some time, and render first executes without having the data populated.
So first time it gets in your render method the value of test = {}. So test.wind.speed will throw an error.
Instead, show a loading state of some sort or simply return null until the call is performed:
render() {
let test = this.state.cityWeather;
if (!test) {
return 'Loading...';
}
....
}
You are accessing the properties too fast since fetch is an asynchronous call it will take some time but your render fires before that already.
Use it like this
{ test && <div>wind speed : {test.wind.speed} </div>}
Initially your test will be null as you haven't received any response from your API so you should check the variable presence before using it. So just check if it is present before using it like this:
render() {
let test = this.state.cityWeather;
return (
<div>
<Toolpanel parentUpdate={this.updateUser} />
<div>wind speed : {test && test.wind && test.wind.speed ? test.wind.speed : ''} </div>
</div>
);
}
Since you didn't post ToolPanel Component implementation, I may be wrong (I'm missing some information). But, I'm also pretty sure that your problem is not having a loading variable.
Basically, the first time render() method is called, you have this.state.cityWeather to be an empty object {}; that is because you fetch the data in componentDidMount(). Thus, the first time render() is called, being this.state.cityWeather empty, you cannot access this.state.cityWeather.wind.speed because you don't have the property wind in this.state.cityWeather!
So, usually, the common way to do this is adding a property loading in the state, and setting it to true in the constructor. Then, in the callback of the fetch, while you set the data in this.state.cityWeather, you also set loading to true.
Finally, in the render() method you wrote a conditional rendering: if this.state.loading === true, then you print a simple paragraph like <p>I'm retrieving info!</p>, otherwhise, if this.state.loading === false, you can render what you want.
componentWillMount() {
console.log('Component WILL MOUNT!')
axios.get('/channels').then( (res) => {
//console.log(res.data.data.playList);
let playlists = [];
res.data.data.playList.map((value, key) => playlists.push(new Audio(value.url)));
this.setState((prevState) => {
return { audioList: playlists, categories: res.data.data.playList }
}, () => console.log(this.state.audioList));
}).catch( (err) => {
console.log(err);
});
}
**I also call this in componentDidUpdate() **
The above code that I used in my ReactJS web app to retrieve data from my DB that looks something like:
{
"_id": {
"$oid": "5a2b903abcf92a362080db4f"
},
"name": "test",
"playList": [
{
"url": "https://p.scdn.co/mp3-preview/a3fd5f178b7eb68b9dba4da9711f05a714efc966?cid=ed36a056ee504173a3889b2e55cbd461",
"artist": "Lil Pump",
"songName": "D Rose",
"_id": {
"$oid": "5a2c5631e54ca10eb84a0053"
}
},
{
"url": "https://p.scdn.co/mp3-preview/155643656a12e570e4dda20a9a24d9da765b9ac5?cid=ed36a056ee504173a3889b2e55cbd461",
"artist": "Tee Grizzley",
"songName": "From The D To The A (feat. Lil Yachty)",
"_id": {
"$oid": "5a2c5631e54ca10eb84a0054"
}
}
],
"__v": 0
}
I retrieve the url for each songs and store it inside my state this.state.audioList to make a playable list.
I access each song with an index
So, this.state.audioList[0] would be the first song.
When I try to play this music by doing
this.state.audioList[0].play(), this totally works fine.
The problem is when I try to pause it.
this.state.audioList[0].pause() does not pause the song for some reason.
I am assuming that it is because the this.state.audioList is getting updated every time and the Audio object that I am trying to pause is a new object that has nothing to do with the one currently being played.
Am I right? If so, is there a solution to this issue?
Please help!
That should work in componentWillMount although componentDidMount is preferred, see : https://reactjs.org/docs/react-component.html#componentdidmount
Quoted from this link (remote endpoint being your axios URL here) :
If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
But you're almost certain that won't work if you put your axios.get() request in componentDidUpdate, because this method is called each time your component has been updated and re-rendered.
From the React Component Lifecycle document, you'll see that componentWillMount and componentDidMount both stay in the Mounting section (that is, they are called only once when the components DOM element are inserted in the DOM), whereas componentDidUpdate is in the Updating section, and therefore is called each time your component's state or props are changed (what happens when your axios.get() promise is fulfilled).
Also, as map returns an array, why not assign its returned value to your audioList ? Here is an example that you may want to try (untested though, sorry !):
componentDidMount() {
console.log('Component DID MOUNT!')
axios.get('/channels').then( (res) => {
//console.log(res.data.data.playList);
this.setState({
audioList: res.data.data.playList.map(value => new Audio(value.url)),
categories: res.data.data.playList
});
}).catch( (err) => {
console.log(err);
});
}
Hope this helps!
I have a meteor app and want to retrieve some data inside a unit test from the client via a headless browser from webdriver.io.
The data I want is from this function:
Session.get() -> http://meteortips.com/first-meteor-tutorial/sessions/
The headless browser I use is from below URL:
http://webdriver.io/
My test looks like this:
describe('[Check Boards]', () => {
it('should exist', () => {
const board = browser.execute('Session.get(\'currentBoard\')');
...
}
}
When i run this command Session.get('currentBoard') inside a real browser console, I get the board as expected.
But when I run it from the code like described above inside a mocha test, I get this result:
{
"state": "success",
"sessionId": "12345",
"hCode": 12345,
"value": null,
"class": "org.openqa.selenium.remote.Response",
"_status": 0
}
The value is null, but there should be the board.
browser.execute expects a function to run in the browser. You're passing in a string, so it probably doesn't know what to do. Here's an updated code snippet that should work:
describe('[Check Boards]', () => {
it('should exist', () => {
const board = browser.execute(function () {
return Session.get('currentBoard');
});
...
}
}
If you're looking for more details, I have an 8 minute video on browser.execute in my WebdriverIO course (#23 in the list).