this is my react code here I fetch the data from the backend using mongo. my data is appearing in the console but not appearing on the web page it's showing `users.map is not a function. but if I try the jsonplaeholder API then its work properly.
import React, { useEffect, useState } from "react";
const Get = () => {
const [users,setUsers] = useState([]);
const getAllUser = async () => {
const response = await fetch("/get");
setUsers(await response.json());
console.log(users);
};
useEffect(() => {
getAllUser();
},[]);
return (
<>
{ users.map((ce) =>
<div key={ce.id}>
<h2>{ce.name}</h2>
<p>{ce.email}</p>
</div>)}
</>
)
}
export default Get;
this is the db data
{"status":"success","results":2,"data":{"users":[{"_id":"6134fcc6eddae0ec522fecd7","name":"ram ","email":"ram#gmail.com","number":9455294552,"__v":0},{"_id":"61364d918a8ab07512094443","name":"rawal","email":"rawal#gmail.com","number":9309304400,"__v":0}]}}
You need to properly set your state with res.data.users as follows.
import React, { useEffect, useState } from "react";
const Get = () => {
const [users, setUsers] = useState([]);
const getAllUser = async () => {
const response = await fetch("/get");
response.json().then((res) => setUsers(res.data.users));
console.log(users);
};
useEffect(() => {
getAllUser();
}, []);
return (
<>
{users.map((ce) => (
<div key={ce.id}>
<h2>{ce.name}</h2>
<p>{ce.email}</p>
</div>
))}
</>
);
};
export default Get;
Related
I'm facing difficulty displaying data in React - Here is my code:
import Axios from 'axios';
import { useNavigate } from 'react-router';
export default function ProductCatalog() {
let navigate = useNavigate();
function addProduct() {
navigate('/adding')
}
const [products, setProducts] = useState([{}])
useEffect(() => {
const axiosProd = async () => {
const response = await Axios('http://localhost:3001/getProducts');
setProducts(response.data)
};
axiosProd();
}, []);
const useProducts = products.map((product)=>{
return <div>
<h1>{product.name}</h1>
</div>
})
return(
<>
<button className = "button" onClick={addProduct}>Add New Product</button>
<br></br>
{useProducts}
</>
)
}
I know data is coming in as JSON Objects as when i follow the link of http://localhost:3001/getProducts, I see my data. What am i doing wrong?
You should make a function then outside of the function call the use effect.
To do a get request using axios use axios.get(api)
For example:
// Get All Shoes
const getShoes = () => {
axios.get('/shoes')
.then(res => setShoes(res.data))
.catch(err => console.log(err));
}
Then
useEffect(() => {
getShoes();
}, [])
I have a function that filters the customers based on their levels (intermediate, beginner ), I'm passing this function through a component that has React select to filter my Data(async)
The filter is working only when I filter the first time but when I choose another value to filter it gave me a blank page?
I tried useEffect to keep it updated but it not working
Do you have any suggestions?
//APP.js
import React,{useState, useEffect} from "react";
import YogaCourses from "./components/YogaCourses/YogaCourses";
import Loading from "./components/IsLoading/Loading";
import LevelsFilter from './components/LevelsFilter/LevelsFilter';
//API to fetch the data
const url = 'https://gist.githubusercontent.com/Tayarthouail/8fb14fe117fdd718ceabd6ee05ed4525/raw/8c86c4bb89fc51667ba0578b2dcba14a0b21f08c/Yoga-courses-api.json';
function App() {
//states
const [yogaCourses, setYogaCourses] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [levels, setLevels] = useState([]);
//Filter by Levels
const filterLevels = (level) => {
const getLevels = yogaCourses.filter((singleLevel)=> singleLevel.level === level.value);
setYogaCourses(getLevels);
}
//Function to fetch the data from the API
const GetCourses = async () => {
const response = await axios.get(url)
const {data} = response;
return data;
}
//UseEffect to run the function on every render
useEffect(()=> {
const GetCoursesYoga = async () => {
const result = await GetCourses();
setYogaCourses(result);
console.log(result);
setLevels(Array.from(new Set(result.map((result)=> result.level))));
}
GetCoursesYoga();
}, []);
//check if the we got response
useEffect(()=> {
if(yogaCourses.length > 0) {
setIsLoading(false);
}
}, [yogaCourses])
if(isLoading) {
return (
<Loading/>
)
}
else {
return (
<main>
<div className="title">
<h2>YOUR PRACTICE REIMAGINED</h2>
</div>
<LevelsFilter levels={levels} filterLevels={filterLevels}/>
<YogaCourses yogaCourses= {yogaCourses}/>
</main>
);
}
}
export default App;
//LevelsFilter component
import React from 'react';
import Select from 'react-select';
import './LevelsFilter.css';
const LevelsFilter = ({levels, filterLevels}) => {
const option = levels.map((level)=> ({value : level, label: level}));
return (
<div>
<Select
options ={option}
className="select-option"
placeholder={"Type..."}
onChange={filterLevels}
/>
</div>
)
}
export default LevelsFilter;
Issue
You are replacing your state with the filtered data and subsequent filtering filters from there, so you only ever reduce your data.
Solution
I suggest storing an active filter state (i.e. level) and do the filtering inline when rendering so you skip the issue of stale/bad state.
function App() {
//states
const [yogaCourses, setYogaCourses] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [levels, setLevels] = useState([]);
const [level, setLevel] = useState('');
const levelChangeHandler = ({ value }) => {
setLevel(value);
}
//Filter by Levels
const filterLevels = (level) => {
return yogaCourses.filter(
(singleLevel) => level ? singleLevel.level === level : true
);
}
...
if(isLoading) {
return (
<Loading/>
)
}
else {
return (
<main>
<div className="title">
<h2>YOUR PRACTICE REIMAGINED</h2>
</div>
<LevelsFilter levels={levels} onChange={levelChangeHandler}/>
<YogaCourses yogaCourses={filterLevels(level)}/>
</main>
);
}
}
LevelsFilter
import React from 'react';
import Select from 'react-select';
import './LevelsFilter.css';
const LevelsFilter = ({ levels, onChange }) => {
const option = levels.map((level)=> ({value : level, label: level}));
return (
<div>
<Select
options ={option}
className="select-option"
placeholder={"Type..."}
onChange={onChange}
/>
</div>
)
}
You need a copy state.
Your code is replacing the data source with filtered data. When you first time selects the option then your state replaces it with that one and you no longer have previous state data. On the second time, you don't have data that why it's blank on-screen.
Just copy and replace the below app.js code:
import React,{useState, useEffect} from "react";
import YogaCourses from "./components/YogaCourses/YogaCourses";
import Loading from "./components/IsLoading/Loading";
import LevelsFilter from './components/LevelsFilter/LevelsFilter';
//API to fetch the data
const url = 'https://gist.githubusercontent.com/Tayarthouail/8fb14fe117fdd718ceabd6ee05ed4525/raw/8c86c4bb89fc51667ba0578b2dcba14a0b21f08c/Yoga-courses-api.json';
function App() {
//states
const [yogaCourses, setYogaCourses] = useState([]);
const [filteredYogaCourses, setFillteredYogaCourses] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [levels, setLevels] = useState([]);
//Filter by Levels
const filterLevels = (level) => {
const getLevels = yogaCourses.filter((singleLevel)=> singleLevel.level === level.value);
setFillteredYogaCourses(getLevels);
}
//Function to fetch the data from the API
const GetCourses = async () => {
const response = await axios.get(url)
const {data} = response;
return data;
}
//UseEffect to run the function on every render
useEffect(()=> {
const GetCoursesYoga = async () => {
const result = await GetCourses();
setYogaCourses(result);
setLevels(Array.from(new Set(result.map((result)=> result.level))));
}
GetCoursesYoga();
}, []);
//check if the we got response
useEffect(()=> {
if(yogaCourses.length > 0) {
setIsLoading(false);
}
}, [yogaCourses])
if(isLoading) {
return (
<Loading/>
)
}
else {
return (
<main>
<div className="title">
<h2>YOUR PRACTICE REIMAGINED</h2>
</div>
<LevelsFilter levels={levels} filterLevels={filterLevels}/>
<YogaCourses yogaCourses= {filteredYogaCourses}/>
</main>
);
}
}
export default App;
I hope it will work, if not then please debug it because I haven't tested it but the idea will be same. :)
Here is my entire component. In the console the correct data is showing up at "data" but when I try to run map on it it says "map is not a function." The 16 items in the console are the correct beaches.
import React, {useState, useEffect} from 'react';
import axios from 'axios';
export default function Beaches() {
const [data, setData] = useState({beaches: []})
// const [hasError, setErrors] = useState(false)
useEffect(() => {
const fetchBeaches = async () => {
const result = await axios('http://localhost:3000/beaches');
setData(result.data);}
fetchBeaches();
}, [])
console.log(data)
return (
<ul>
{data.beaches.map(beach => (
<button>{beach.name}</button>
))}
</ul>
)
}
Because you're not setting the beaches data in state correctly.
Replace useEffect code with this:
useEffect(() => {
const fetchBeaches = async () => {
const result = await axios('http://localhost:3000/beaches');
setData({beaches: result.data});
}
fetchBeaches();
}, [])
furthermore, you can improve the state structure of beaches data:
import React, { useState, useEffect } from "react";
import axios from "axios";
export default function Beaches() {
const [beaches, setBeaches] = useState([]);
// const [hasError, setErrors] = useState(false)
useEffect(() => {
const fetchBeaches = async () => {
const result = await axios("http://localhost:3000/beaches");
setBeaches(result.data);
};
fetchBeaches();
}, []);
return (
<ul>
{beaches.map((beach) => (
<button>{beach.name}</button>
))}
</ul>
);
}
The useEffect below renders, fetches data, and displays it once (using an empty array for 2nd parameter in useEffect).
I need it to rerun useEffect everytime the user changes data to the database (when user uses axios.post).
What i've tried
using [tickets], but that just causes the useEffect to run infinitly
also using [tickets.length] and [tickets, setTickets]
trying to use props as parameter but didnt find anything useful
import React, { useState, createContext, useEffect } from "react";
import axios from "axios";
export const TicketContext = createContext();
export const TicketProvider = (props) => {
console.log(props);
const [tickets, setTickets] = useState([]);
useEffect(() => {
getTickets();
console.log("1", { tickets });
}, []);
const getTickets = async () => {
const response = await axios.get("http://localhost:4000/tickets/");
setTickets(response.data);
};
return <TicketContext.Provider value={[tickets, setTickets]}>{props.children}
</TicketContext.Provider>;
};
import React from "react";
import { useState, useEffect, useContext } from "react";
import Ticket from "../Ticket";
import { TicketContext } from "../contexts/TicketContext";
import AddBacklog from "../addData/AddBacklog";
const TicketDisplay = (props) => {
const [tickets, setTickets] = useContext(TicketContext);
return (
<div className="display">
<p>Antony Blyakher</p>
<p>Number of Tickets: {tickets.length}</p>
<div className="backlog">
<h1>Backlog</h1>
{tickets.map((currentTicket, i) => (
<div className="ticketBlock">
<Ticket ticket={currentTicket} key={i} />
</div>
))}
</div>
</div>
);
const AddBacklog = (props) => {
const [tickets, setTickets] = useState("");
...
axios.post("http://localhost:4000/tickets/add", newTicket).then((res) => console.log(res.data));
setTickets((currentTickets) => [...currentTickets, { name: name, status: "backlog", id: uuid() }]);
};
You'll need to watch for tickets and return if it has data to not cause infinite loop:
useEffect(() => {
if (tickets.length) return // so, we call just once
getTickets();
console.log("1", { tickets });
}, [tickets]);
const fetchData = () => {
axios.get("http://localhost:7000/api/getData/").then((response) => {
console.log(response.data);
if (response.data.success) {
SetIsLoading(false);
}
setDataSource(response.data.data);
});
};
useEffect(() => {
fetchData();
if (fetchData.length) fetchData();
}, [fetchData]);
by this you can fetch the data in real-time as any change in data occurs.
I'm trying to take out the fetchImages function from the following component and put it inside a new component:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import UnsplashImage from './UnsplashImage';
const Collage = () => {
const [images, setImages] = useState([]);
const [loaded, setIsLoaded] = useState(false);
const fetchImages = (count = 10) => {
const apiRoot = 'https://api.unsplash.com';
const accessKey =
'<API KEY>';
axios
.get(`${apiRoot}/photos/random?client_id=${accessKey}&count=${count}`)
.then(res => {
console.log(res);
setImages([...images, ...res.data]);
setIsLoaded(true);
});
};
useEffect(() => {
fetchImages();
}, []);
return (
<div className="image-grid">
{loaded
? images.map(image => (
<UnsplashImage
url={image.urls.regular}
key={image.id}
alt={image.description}
/>
))
: ''}
</div>
);
};
export default Collage;
For this, I created a new component called api.js, removed the entire fetchImage function from the above component and put it in to api.js like this:
api.js
const fetchImages = (count = 10) => {
const apiRoot = 'https://api.unsplash.com';
const accessKey =
'<API KEY>';
axios
.get(`${apiRoot}/photos/random?client_id=${accessKey}&count=${count}`)
.then(res => {
console.log(res);
setImages([...images, ...res.data]);
setIsLoaded(true);
});
};
export default fetchImages;
Next I took setIsLoaded(true); from api.js and paste it inside Collage component like this:
useEffect(() => {
fetchImages();
setIsLoaded(true);
}, []);
Now I can import fetchImages in to Collage component.
However, I don't know what should I do with this line inside the fetchImages function? This needs to go to Collage component, but res.data is not defined inside Collage component.
setImages([...images, ...res.data]);
How should I handle it?
There is many way to do that, but in your case.
You should use
const fetchImages = (afterComplete, count = 10) => {
const apiRoot = 'https://api.unsplash.com';
const accessKey = '<API KEY>';
axios
.get(`${apiRoot}/photos/random?client_id=${accessKey}&count=${count}`)
.then(res => {
console.log(res);
afterComplete(res.data);
});
};
export default fetchImages;
And in your Collage component:
const afterComplete = (resData) =>{
setImages([...images, ...resData]);
setIsLoaded(true);
}
useEffect(() => {
fetchImages(afterComplete);
}, []);
What you can do is create a custom hook ( sort of like a HOC)... Since I don't have an unsplash API key I'll give you an example with a different API but the idea is the same:
Here is your custom hook:
import { useState, useEffect } from 'react';
export const useFetch = url => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const fetchUser = async () => {
const response = await fetch(url);
const data = await response.json();
const [user] = data.results;
setData(user);
setLoading(false);
};
useEffect(() => {
fetchUser();
}, []);
return { data, loading };
};
Here is how you can use it in your component:
import { useFetch } from './api';
const App = () => {
const { data, loading } = useFetch('https://api.randomuser.me/');
return (
<div className="App">
{loading ? (
<div>Loading...</div>
) : (
<>
<div className="name">
{data.name.first} {data.name.last}
</div>
<img className="cropper" src={data.picture.large} alt="avatar" />
</>
)}
</div>
);
};
Here is a live demo: https://codesandbox.io/s/3ymnlq59xm