React not being able to acess a query value - json

Hey i am trying to access whats inside of a fetch trought item.name and so on..
I would like to know why i am not being able to access the item properties
However i am not getting anythign back in the return statement, this is the json i need to access.
{"message":{"_id":"5ea9c860ea9fb600178ae676","name":"frutology","description":"frutas"}}
import React, {useState,useEffect} from 'react';
function StoreDetails ({ match }) {
useEffect(()=>{
fetchItem();
},[]);
const[item,setItem]=useState({name: "", description : ""});
const fetchItem = async() => {
const fetchItem = await fetch(
`/storedisplay/${match.params.id}`
);
const item = await fetchItem.json();
setItem(item);
console.log(item);
}
return (
<div>
<h1>{item.name}</h1>
<h2> {item.description}</h2>
</div>
);
}
export default StoreDetails;

Keep in mind that useState is asynchronous.
Use useEffect.
useEffect(() => {
console.log(item);
}, [item])

Related

Why am i only seeing "id" in my react app when the fetch get all the data from Strapi?

i am trying Strapi for the first time, and i cant put my raw data into my divs.
On Strapi everything is published, and for the public the get and getOne is checked.
This way i can only see the "id" nothing else.
Any guess?
here is my result from fetch:
Here is the code that i got from the tutorial page:
import { useEffect, useState } from 'react';
import "./App.css"
// Parses the JSON returned by a network request
const parseJSON = (resp) => (resp.json ? resp.json() : resp);
// Checks if a network request came back fine, and throws an error if not
const checkStatus = (resp) => {
if (resp.status >= 200 && resp.status < 300) {
return resp;
}
return parseJSON(resp).then(resp => {
throw resp;
});
};
const App = () => {
const [error, setError] = useState(null);
const [restaurants, setRestaurants] = useState([]);
useEffect(() => {
fetch('http://localhost:1337/api/restaurants', { headers:{ 'Content-Type': 'application/json' },
method: 'GET' })
.then(checkStatus)
.then(parseJSON)
.then(({ data }) => setRestaurants(data))
.catch((error) => setError(error))
}, [])
if (error) {
// Print errors if any
return <div>An error occured: {error.message}</div>;
}
return (
<div>
<div>
{restaurants.map(({ id, name, description }) => (
<div className="black" key={id}>
{name}
{description}
{id}
</div>
))}
</div>
</div>
);
};
export default App;
I figured it out forom Google.
The map section needs to be changed to this:
{restaurants && restaurants.map((restaurant) => (
<div className="black" key={restaurant.id}>
{restaurant.attributes.name}
{restaurant.attributes.description}
{restaurant.id}
{restaurant.attributes.publishedAt}
</div>
))}

How to loop through a JSON array with useEffect in React?

I am trying to loop through a JSON array with useEffect. When I use the below code (with the array removed from useState) with a single user specified, I am able to get the data. However it does not work with the entire array...any suggestions would be appreciated.
function GitHubUser() {
const [data, setData] = useState([]);
useEffect(() => {
fetch(`https://api.github.com/users/`)
.then(res => res.json())
.then(setData)
.catch(console.error);
}, []);
if (data) {
return (
<div>
<h1>{data.userId}</h1>
<img src={data.avatar_url} width={100} alt={"github avatar"}/>
<p>{data.login}</p>
</div>
);
}
return null;
}
It doen't work because when you do if (data) it returns true because empty array is true
const data = [];
if (data) {
console.log("Empty array is true");
} else {
console.log("Empty array is false");
}
So... when you try to get userId from an empty array it throws an error.
If data is supposed to be an array...
function GitHubUser() {
const [data, setData] = useState([]);
useEffect(() => {
fetch("https://api.github.com/users")
.then((res) => res.json())
.then(setData)
.catch(console.error);
}, []);
if (data) {
return (
<React.Fragment>
{data.map((user) => (
<div>
<h1>{user.userId}</h1>
<img src={user.avatar_url} width={100} alt={"github avatar"} />
<p>{user.login}</p>
</div>
))}
</React.Fragment>
);
}
return null;
}
You have to map each user to the expected output component. Using a map will prevent the previous behaviour because if no elements are present in the array, it will not map anything and return an empty component instead of an error.
If data is not supposed to be an array, then you shouldn't use a map nor initialize the state with an empty array because before running the fetch it will try to render the component and fail.
Is this something like you u want?
I removed the backslash after https://api.github.com/users*here*.
I set the data in useEffect hooks, in your example you didnt do it.
And mapped the array in data, it shows all the github users with
images and names.
.
function GitHubUser() {
const [data, setData] = useState([]);
useEffect(() => {
fetch(`https://api.github.com/users`) // removed the backslash here
.then(res => res.json())
.then(data => setData(data)) // changed this line
.catch(console.error);
}, []);
console.log(data)
return (
<div>
{data.map((item, key) => <> // Mapping through the array here
<h1 key={key}>{item.id}</h1>
<img src={item.avatar_url} width={100} alt={"github avatar"}/>
<p>{item.login}</p>
</>
)}
</div>
);
}

access the data of a hook- React

I am requesting this API, then I save the result in the "data" hook. when I want to print "data.total_results" everything ok but when I want to print a key that has more data inside it doesn't leave me "Data.results [0] .title"
import React, { useState, useEffect } from 'react';
const Movie = () => {
// Declara una nueva variable de estado, que llamaremos "count".
const [Data, setData] = useState("");
useEffect(() => {
const Cargar = async () => {
let respuesta = await fetch("https://api.themoviedb.org/3/discover/movie?api_key=ce322f54257cc9286282b320c5e9b2a0&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1");
let respuestaJSON = await respuesta.json();
setData(respuestaJSON);
};
Cargar();
}, [Data]);
return (
<div>
{Data.total_results}
{/* {Data.results[0].title} */}
</div>
);
}
export default Movie;
You need to check if the results property is defined.
<div className="App">
<h1>Total {Data.total_results}</h1>
{typeof Data.results !== "undefined" &&
Data.results.map((movie, index) => {
return <h3>{movie.title}</h3>;
})}
</div>
Working Demo: https://codesandbox.io/s/distracted-feather-4l55r
A few days back, I have created a repository and implemented OMDB API with React. This may help you.
https://github.com/jogeshpi03/omdb-react
Your code is almost right. There's a bug and a couple improvements you can make.
First let's take a look at the useEffect hook.
useEffect takes two arguments: a function, and a list of dependencies. The first time the component is rendered, and when any of the dependencies change, the function argument will be executed again.
So right now you have a bug with your dependencies that is causing an infinite loop. When the component is rendered, you execute the function in useEffect. That function will eventually set Data. When the value for Data is set, that will cause the useEffect function to be executed again. Which will set a new value to Data, which will execute the function again, ad infinitum.
The fix is to set the dependencies to [] if you only want that to run once. Like this:
useEffect(() => {
const Cargar = async () => {
let respuesta = await fetch("https://api.themoviedb.org/3/discover/movie?api_key=ce322f54257cc9286282b320c5e9b2a0&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1");
let respuestaJSON = await respuesta.json();
setData(respuestaJSON);
};
Cargar();
}, []); // <-------- This changed to []
I hope that fixes your issue.
Now I will suggest some improvements:
I would set the initial state of Data to undefined
const [Data, setData] = useState();
and then use a conditional in the JSX like so
if (!Data) {
return <div>Loading...</div>
}
return (
<div>
{Data.total_results}
</div>
);
const [Data, setData] = useState([]);
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import ReactTable from 'react-table'
import 'react-table/react-table.css'
const Movie = () => {
// Declara una nueva variable de estado, que llamaremos "count".
const [Data, setData] = useState([]);
useEffect(() => {
axios.get("https://api.themoviedb.org/3/discover/movie?api_key=ce322f54257cc9286282b320c5e9b2a0&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1")
.then(function(response) {
console.log(response.data.results)
setData(response.data.results);
}).catch(function(error) {
console.log(error);
})
}, []);
return (<div>
{Data.map(function (row, i) {
return <div key={i}>
{row.title}
</div>
})}
</div>)
}
export default Movie;

How can I turn a function used in many components into its own component which I can reuse across the app?

I have a fetch request used on multiple pages, and would like to turn it into a component to simply call in whenever it's needed. This is proving to be harder than I thought, and it's bring up a number of issues.
I have tried using the wrappedComponent function but not sure if that's the solution as it's still not working. It's now saying that the fetchPosts class constructor cannot be invoked without new.
const that = this;
fetch ('/testrouter')
.then (response => {
return response.json();
}).then(jsonData => {
that.setState({posts:jsonData})
}).catch(err => {
console.log('Error fetch posts data '+err)
});
}
This is what I want to turn into a component, so that I can just call it by it's name from another one inside componentDidMount. I have tried doing this:
function fetchPosts(WrappedComponent) {
class FetchPosts extends Component {
constructor(props) {
super(props)
this.state = {
posts: []
}
}
fetchAllPosts() {
const that = this;
fetch ('/testrouter')
.then (response => {
return response.json();
}).then(jsonData => {
that.setState({posts:jsonData})
}).catch(err => {
console.log('Error fetch posts data '+err)
});
}
render() {
return (<WrappedComponent
fetchAllPosts = {this.fetchAllPosts})
/>);
}
}
return FetchPosts;
}
export default fetchPosts
Then importing it and calling it with fetchPosts but it's not working.
I was hoping I would be able to create a component, add the code then import the component, but this is not working.
You might want to create a custom hook to do this:
useFetch.jsx
import React, { useState, useEffect } from 'react'
const useFetch = (url) =>
const [state, setState] = useState({ loading: true, data: null, error: null })
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => setState(state => ({ ...state, loading: false, data }))
.catch(error => setState(state => ({ ...state, loading: false, error }))
},[])
return state
}
export default useFetch
MyComponent.jsx
import React from 'react'
import useFetch from './useFetch.jsx'
const MyComponent = () => {
const data = useFetch('/testrouter')
return (<>
{ data.loading && "Loading..." }
{ data.error && `There was an error during the fetch: {error.message}` }
{ data.data && <Posts posts={data.data}/> }
</>)
}

Making an API call in React

I am trying to make an API call in React to return JSON data but I am a bit confused on how to go about this. My API code, in a file API.js, looks like this:
import mockRequests from './requests.json'
export const getRequestsSync = () => mockRequests
export const getRequests = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(mockRequests), 500)
})
It is retrieving JSON data formatted like this:
{
"id": 1,
"title": "Request from Nancy",
"updated_at": "2015-08-15 12:27:01 -0600",
"created_at": "2015-08-12 08:27:01 -0600",
"status": "Denied"
}
Currently my code to make the API call looks like this:
import React from 'react'
const API = './Api.js'
const Requests = () => ''
export default Requests
I've looked at several examples and am still a bit confused by how to go about this. If anyone could point me in the right direction, it would be greatly appreciated.
EDIT: In most examples I've seen, fetch looks like the best way to go about it, though I'm struggling with the syntax
Here is a simple example using a live API (https://randomuser.me/)... It returns an array of objects like in your example:
import React from 'react';
class App extends React.Component {
state = { people: [], isLoading: true, error: null };
async componentDidMount() {
try {
const response = await fetch('https://randomuser.me/api/');
const data = await response.json();
this.setState({ people: data.results, isLoading: false });
} catch (error) {
this.setState({ error: error.message, isLoading: false });
}
}
renderPerson = () => {
const { people, isLoading, error } = this.state;
if (error) {
return <div>{error}</div>;
}
if (isLoading) {
return <div>Loading...</div>;
}
return people.map(person => (
<div key={person.id.value}>
<img src={person.picture.medium} alt="avatar" />
<p>First Name: {person.name.first}</p>
<p> Last Name: {person.name.last}</p>
</div>
));
};
render() {
return <div>{this.renderPerson()}</div>;
}
}
export default App;
Does it make sense? Should be pretty straight forward...
Live Demo Here: https://jsfiddle.net/o2gwap6b/
You will want to do something like this:
var url = 'https://myAPI.example.com/myData';
fetch(url).then((response) => response.json())
.then(function(data) { /* do stuff with your JSON data */})
.catch((error) => console.log(error));
Mozilla has extremely good documentation on using fetch here that I highly recommend you read.
The data parameter in the second .then will be an object parsed from the JSON response you got and you can access properties on it by just using the property label as was in the JSON. For example data.title would be "Request from Nancy".
If you are struggling with fetch, Axios has a much simpler API to work with.
Try this in your API.js file (of course install axios first with npm i --save axios):
import axios from 'axios'
import mockRequests from './requests.json'
export const getRequests = (url) => {
if (url) {
return axios.get(url).then(res => res.data)
}
return new Promise((resolve, reject) => { // you need to return the promise
setTimeout(() => resolve(mockRequests), 500)
})
})
In your component, you can access the getRequests function like so
import React, { Component } from 'react'
import { getRequests } from './API.js'
class App extends Component {
state = {
data: null
}
componentWillMount() {
getRequests('http://somedomain.com/coolstuff.json').then(data => {
console.log(data)
this.setState({ data })
})
}
render() {
if (!this.state.data) return null
return (
<div className='App'>
{this.state.data.title}
</div>
)
}
}
export default App