Im trying to mock a Plant API by using a db.json file (relative path: src\plant-api\db.json), and passing it from the parent component (ItemList) to its child (Item) but its not working because i see no data displayed on screen even tho i can see it in my console.log.
Heres the full code
import React, { useState, useEffect } from "react";
import Item from "./Item";
import Data from "../plant-api/db.json"
const ItemList = () => {
const [plants, setPlants] = useState([]);
useEffect(() => {
fetch(Data)
.then((response) => response.json())
.then((data) => setPlants(data));
}, []);
console.log(Data)
return (
<div className="items">
{plants.map((plant) => {
return (
<div>
<Item data={plant} />
</div>
);
})}
</div>
);
};
export default ItemList;
import React from "react";
import ItemCount from "./ItemCount";
const Item = ({ data }) => {
return (
<div>
<div className="item">
<img src={data.pic} alt="plant-image" />
<h3>{data.name}</h3>
<p>{data.category}</p>
<h4>{data.price}</h4>
<ItemCount stock="10" initial="0" />
</div>
</div>
);
};
export default Item;
directory structure
Any help is needed and appreciated!
maybe you can use the json-server package, so you can create a dummy API,.
an example of using code like the one below in the terminal, make sure the code is run in the db.json file directory.
npx json-server db.json -p2000
later there will be a json server running as an API on port 2000
fetch is used to make network calls, but since you have already have Data imported, you can just set the data in your useEffect hook: setPlants(Data); This should be enough if you're just trying to see how the data renders.
If your data is already in JSON format, you don't need to use a fetch, you can just pop it straight into the const [plants, setPlants] = useState(Data).
If you're trying to simulate a live API, you will have to create a dummy API as Dedi mentioned.
Related
I'm running into a problem in development where the page finishes loading before the data gets sent from the API. I've tried using asynchronous functions but that doesn't help even though I'm sure it should. I think I might be doing it wrong. Below is an example of a page in my app where I am experiencing this issue:
import React, {useEffect, useState} from 'react';
import { useRouter } from 'next/router';
import axios from 'axios';
import Link from 'next/link';
import { Card,
Button
} from 'react-bootstrap';
export default function SingleTour() {
const [tour, setTour]= useState({});
const [tourShows, setTourShows] = useState({});
const router = useRouter();
const {slug} = router.query;
useEffect( () => {
let enpoints = [
`http://localhost:3000/tours/${slug}`,
`http://localhost:3000/listshows/${slug}`
]
axios.all(
enpoints.map((endpoint) =>
axios.get(endpoint)))
.then(response => {
console.log(response)
setTour(response[0].data)
setTourShows(response[1].data)
})
.catch(error => console.log(error))
}, [slug])
console.log(tour);
return (
<div className='container'>
<div>
<h1></h1>
</div>
<h3>Shows</h3>
<div className='card-display'>
{tourShows.data ? (
tourShows.data.map(({attributes, id}) => (
<Link href={`/shows/${id}`} passHref key={id}>
<Card border="secondary" style={{ width: '18rem', margin: '1rem'}}>
<Card.Body>
<Card.Title>Show {id}</Card.Title>
<Card.Text>{attributes.date}</Card.Text>
<Card.Text>{attributes.location}</Card.Text>
<Card.Text>Head Count {attributes.headcount}</Card.Text>
</Card.Body>
</Card>
</Link>
))
) : 'LOADING ...'}
</div>
</div>
)
}
Any help is greatly appreciated. I am also using Next JS if that makes a difference.
If you use useEffect hook it is expected that you will have a render before the hook fires to fetch the data, that is the way useEffect works.
If you want to fetch your data inside the next app you have to use getServerSideProps instead, fetch the data there and pass that as a prop to the component. See the docs here: https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props
This is the way React works. useEffect will attempt to fetch the data and React will continue doing it's business, render the component. You can put an if statement at the beginning of the return statement, for instance checking the length of the tourShows.data, it the length is 0 return nothing, otherwise return as you do now.
I'm making a Hacker rank clone project in React, and so far I tried to get all the New Posts from the API.
Since the API only gives me id's I was just able to map over the piece of state that holds that information. But now I want to get the whole data from every id that I got , and then display all the posts. It's been really confusing for me, and i really need some help. Well, to resume everything: I got the id's from a api call and stored it in my state. Now I want to get all of the id's and make another request, but this time I'll get the info based on that specific Id. Here's the code:
import React, { useState } from "react";
import "./styles.css";
import TopList from "./components/TopList";
export default function App() {
const [state, setState] = useState({
data: [23251319, 23251742, 23251158],
results: []
});
const fetcher = id => {
fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`)
.then(res => res.json())
.then(data => {
console.log(data);
setState({
results: data
});
});
};
return (
<div>
<TopList data={state.data} fetcher={fetcher} />
</div>
);
}
import React from "react";
import Top from "./Top";
function TopList({ data, fetcher }) {
const mapped = data.map(item => (
<Top fetcher={fetcher} id={item} key={item} />
));
return <div>{mapped}</div>;
}
export default TopList;
import React from "react";
function Top({ id, fetcher }) {
fetcher(id);
return (
<div>
<h1>Hello from top</h1>
</div>
);
}
export default Top;
As I told you in the comments, the fetcher() function already gets the data of each item using the IDs you have from the first request. I think that a good place to call this function is the TopStoryComponent, as there will be an instance of this component for each ID in the list.
import React from "react";
function TopStoryComponent({ identification, fetcher }) {
// this will print the data to the console
fetcher(identification);
return <div>{identification}</div>;
}
export default TopStoryComponent;
Let me know if it helps you get what you need!
I am fetching a list of directories via firebase storage, and then once that has finished, return a list of Project components to be rendered, each with the name retrieved before. How do you first wait for the fetching to complete and then return the same number of Project components?
This is what I have tried:
import React, {useState} from "react"
import "./index.css"
import {hot} from "react-hot-loader"
import Project from "./Project"
import firebase from "./Firebase.js"
function Projects(props){
// Get refereance to firebase storage
let storage = firebase.storage();
// Reference the main projects folder
let storageRef = storage.ref().child('projects');
// Store all project names from firebase storage to then return them as Project components
let projects = []
// This lists the directories in 'Projects'
storageRef.listAll().then(res => {
// For each directory, push the name into the projects array
res.prefixes.forEach((folderRef) => {
projects.push(folderRef.name)
})
}).catch(error => {
console.log(error)
})
return(
<div>
{projects.map(projName => (
<>
<Project project={projName}/>
</>
))}
</div>
)
}
export default hot(module)(Projects)
However, when projects is returned, it is empty as it hasn't waited for the forEach to finish above. Plus, I don't think the return statement within projects.map() is working. I have attempted a Promise and Async Await but am not sure how to structure it.
Similar to class components, you will need to define your state using the useState hook in functional components.
In addition, you should use the useEffect hook to handle the carrying out the HTTP request such that it will not be triggered on every re-render. We added an empty array ([]) as the second parameter of the useEffect hook, such that it will only be run once, as explained on the official React hooks documentation.
After the responses have been returned, we update the state by calling setProjects().
function Projects(props){
const [ projects, setProjects ] = useState([]);
let storage = firebase.storage();
let storageRef = storage.ref().child('projects');
useEffect(() => {
const response = []
storageRef.listAll().then(res => {
// For each directory, push the name into the projects array
res.prefixes.forEach((folderRef) => {
response.push(folderRef.name)
})
setProjects(response);
}).catch(error => {
console.log(error)
})
}, [])
return(
<div>
{projects.length && projects.map((projName, index) => (
<Project project={projName} key={index} />
))}
</div>
)
}
export default hot(module)(Projects)
I'm trying to fetch data from a server using the fetch api and displaying this data in an unordered list using uuidv4 as the key, im trying to do this using react's useEffect hook, however, it fetches the data but then it says all my keys are the same, i think useEffect is the cause and i tried adding as the second argument an empty array to prevent the rerendering but then its saying im missing a dependency and when i put the dependency in it rerenders and the uuid's are the same again. i'm not sure what to do im relatively new to hooks.
import React, { useState, useEffect } from "react";
import "./App.css";
const uuidv4 = require("uuid/v4");
function App() {
const [country, setCountry] = useState({
country: []
});
useEffect(() => {
console.log("fetching data");
fetch("http://localhost:5000/country")
.then(res => res.json())
.then(data => setCountry({...country, country: data }));
}, []);
return (
<>
<ul>
{country.country.map(item => {
return <li key={uuidv4}>{item.name}</li>;
})}
</ul>
</>
);
}
export default App;
I think you have to call it to generate the uuid:
return <li key={uuidv4()}>{item.name}</li>;
Best way to assign or set the keys when you map over a list is to use index, which you can get from map
return (
<>
<ul>
{country.country.map((item, index) => {
return <li key={index}>{item.name}</li>;
})}
</ul>
</>
);
i have JSON like this
i want to use this JSON and display data in Table using react js.
this is how i display data from JSON file.
import React, { Component } from 'react';
import data from './data.json';
class App extends Component {
render() {
return (
<ul>
{
data.map(function(movie){
return <li>{movie.id} - {movie.title}</li>;
})
}
</ul>
);
}
}
export default App;
how to load JSON from URL and display it in table using reactjs?
You could fetch the JSON once the component will mount, and when you eventually resolve it you can update the state of the component:
import React, { Component } from 'react';
class App extends Component {
// initially data is empty in state
state = { data: [] };
componentDidMount() {
// when component mounted, start a GET request
// to specified URL
fetch(URL_TO_FETCH)
// when we get a response map the body to json
.then(response => response.json())
// and update the state data to said json
.then(data => this.setState({ data }));
}
render() {
return (
<ul>
{
this.state.data.map(function(movie){
return <li key={movie.id}>{movie.id} - {movie.title}</li>;
})
}
</ul>
);
}
}
export default App;
If you're unable to use fetch, you could use some other libraries like superagent or axios. Or you could even fall back to good ol' XMLHttpRequest.
On another note, when building a list of component it is important they each child have a unique key attribute. I also updated that in the code, with the assumption that movie.id is
Example axios code:
axios.get(URL)
.then(response => response.data)
.then(data => this.setState({ data }));
EDIT: as trixn wrote in a reply, componentDidMount is the preferred place to fetch data. Updated code.
EDIT 2: Added axios code.
You can use axios to send http requests.
It looks like this :
const response = await axios.get(your_url_here);
const items = response.data.items;
About await keyword : How to use await key word on react native?
This is axios GitHub page for the docs : https://github.com/axios/axios
Hope it helps.
You can use the fixed Data table to display the data from the json Response.Since the data is vast and it would be difficult to manage the conventional table, this would be a better alternative.
The documentation is given at
https://github.com/schrodinger/fixed-data-table-2/blob/master/examples/ObjectDataExample.js
This link will help you.