Why is my React Use-Effect Hook Not Working? - reactjs

I am re-posting a question I asked a week ago where I left out the steps I took to solve the issue. I am working on a simple MERN app off a tutorial and the use-effect function is not rendering the content onto the page. Here is the code:
App.js File
import './App.css';
import { useState, useEffect } from 'react';
import Axios from 'axios';
function App() {
const [listOfUsers, setListOfUsers] = useState([]);
useEffect(() => {
Axios.get("http://localhost:3001/getUsersFakeDataGen").then((response) => {
setListOfUsers(response.data)
})
}, [])
return (
<div className="App">
<div className="usersDisplay">
{listOfUsers.map((user) => {
return (
<div>
<h1>Name: {user.name}</h1>
<h1>Age: {user.age}</h1>
<h1>Username: {user.username}</h1>
</div>
)
})}
</div>
</div>
)
};
export default App;
I tested the functionality by commenting out the "useEffect()" function and putting in an object in the "useState([])" element of "function App()". That object did correctly render on the page, but when I deleted that object and un-commented useEffect(), the page was blank again.
I confirmed that my APIs are working because my API client (Thunder Client) is showing that the GET and POST requests are reading and writing to the database (MongoDB). Also, the server is working properly (confirmed by a console log).
Any suggestions would be appreciated. If more information is needed, please let me know. Thank you.

if your problem is not resolved, yet I suggest the following:
import axios from 'axios'
...
const [listOfUsers, setListOfUsers] = useState([]);
const fetchData = async () => {
const result = await axios.get("http://localhost:3001/getUsersFakeDataGen").then((response) => {
setListOfUsers(response.data)
return response.data;
});
useEffect(() => {
fetchData();
}, [])
Note [] in the useEffect, it means it will render only once when the page loads. Also I used async and await to wait for data to be retrieved before processing (maybe that's why you get empty elements). You can also setState outside of useEffect.

import './App.css';
import { useState, useEffect } from 'react';
import Axios from 'axios';
function App() {
const [listOfUsers, setListOfUsers] = useState([]);
useEffect(() => {
Axios.get("http://localhost:3001/getUsers").then((response) => {
setListOfUsers(response.data)
})
}, [listOfUsers]); // THIS IS WHERE YOU ADD YOUR useEffect DEPENDENCIES
return (
<div className="App">
<div className="usersDisplay">
{listOfUsers.map((user) => {
return (
<div>
<h1>Name: {user.name}</h1>
<h1>Age: {user.age}</h1>
<h1>Username: {user.username}</h1>
</div>
)
})}
</div>
</div>
)
};
export default App;
OK look so the issue is if you only provided an empty array as your second argument. Your useEffect will only run one time, when you add stateful values to the array the useEffect will render every time that piece of state changes. If you omit the second argument the useeffect will run over and over again.
Also here-- Remember that you array starts empty, You need a check it's existence
{listOfUsers?.map.map((item))=>{}}
or
{listOfUsers.length && listOfUsers.map((item))=>{}}
.
{listOfUsers.map((user) => {
return (
<div>
<h1>Name: {user.name}</h1>
<h1>Age: {user.age}</h1>
<h1>Username: {user.username}</h1>
</div>
)
})}

Related

How to show loading only after making a api request?

In my react Project,
There is a button. When clicking on it, it will start making an API request.
Right now, on the first page load, there is already a "Loading" showing, even before I click the right button.
Q1: How can I only show the "Loading" only after I set the click loading butting?
(For some reason, I am not able to use setLoading state to do this)
Q2:Even thought this example may seem so trivial, but taking the consideration that if the return is Error or resolved, there may be different handling, even thought I havent shown it in the example yet.
I have read some online doc, it said I may need to use useReducer for this. But I am not so sure how.
Notice: Much appreciate if could provide answer by using useReducer approach
Below is my code
import React , {useState, useEffect}from 'react';
import axios from 'axios';
export function App(props) {
const [post, setPost]= useState('')
useEffect(()=>{console.log(post)})
const handle = () => {
axios.get('https://jsonplaceholder.typicode.com/todos/1').then((response) => {
setPost(response.data);
});
}
return (
<div className='App'>
<button onClick={handle}>Load data</button>
{post? <ul>
<li>{post.userId}</li>
<li>{post.id}</li>
<li>{post.title}</li>
</ul>:<p>Loading</p>
}
</div>
);
}
=====================
Edited:
I have updated the code, but now I am stuck with the situation that when the loading is set to be true, the databoard is gone then
import React , {useState, useEffect}from 'react';
import axios from 'axios';
export function App(props) {
const [post, setPost]= useState('')
const [loading,setLoading]= useState(false);
useEffect(()=>{console.log(post)})
const handle = () => {
//before do the api call
//set the loading
setLoading(true);
axios.get('https://jsonplaceholder.typicode.com/todos/1').then((response) => {
setPost(response.data);
//set the loading to be false as loading is done
setLoading(false);
}).catch((err) => {
//error state
//set the loading to be false as loading is done
setLoading(false);
});
;
}
return (
<div className='App'>
<button onClick={handle}>Load data</button>
{loading? <Databoard post={post}>
</Databoard>:null
}
</div>
);
}
const Databoard = (props) => {
const {post}=props
return <ul>
<li>{post.userId}</li>
<li>{post.id}</li>
<li>{post.title}</li>
</ul>
}
You simply need a state variable using which you can judge what to show to the user.
const [loading,setLoading]= useState(false);
const handle = () => {
setLoading(true); axios.get('https://jsonplaceholder.typicode.com/todos/1').then((response) => {
setPost(response.data);
setLoading(false);
}).catch((err) => {
//error state
setLoading(false);
});
}
Use the variable in your return statement to handle the jsx

How to populate my const before the page renders?

I'm pretty new to ReactJS dev and today i'm trying to get some data from an API using Axios. My issue is :
I'm trying to de map function on resultData to get what i want inside, but an error is proped and it's showing : resultData.map is not a function
If i comment this part of the code and just render the page first, then uncomment, it works and data are shown.
I'm assuming that data is not loaded before the rendering process is over so that's why i get this. But how to make it load before ?
Here my code snippets :
import React, { useState, useEffect } from "react";
import "./App.css";
import axios from "axios";
const Url = "someAPi";
function App() {
const [baseData, setBaseData] = useState({});
const [resultData, setResultData] = useState({});
useEffect(() => {
getBaseDataWithAxios();
}, []);
const getBaseDataWithAxios = async () => {
const response = await axios.get(Url);
setBaseData(response.data);
};
useEffect(() => {
getResultDataWithAxios();
}, []);
const getResultDataWithAxios = async () => {
const response = await axios.get(Url);
setResultData(response.data.result);
};
const listItems =
resultData.map((d) => <li key={d.value}>{d.value}</li>);
return (
<div className="App">
<header className="App-header">
<h2>generated fees</h2>
</header>
<div className="info-container">
<h5 className="info-item">{baseData.status}</h5>
<h5 className="info-item">{baseData.message}</h5>
<h5 className="info-item">{listItems[1]}</h5>
</div>
</div>
);
}
export default App;
The error is thrown on this :
const listItems =
resultData.map((d) => <li key={d.value}>{d.value}</li>);
I know my data can be read since if i comment the listItems and the displaying part in the return, render the page, uncomment everything, it displays the data properly.
Can someone explain to me how to populate data first ? During my research i've seen that this can happen by using Axios.
Thanks a lot !
The useEffect hook always runs after your component function returns in the render cycle.
Try an empty array for your initial value of resultData instead of an empty object:
const [resultData, setResultData] = useState([]);
There is no map built-in method on non-array objects, so during the first execution, you receive that error.

React - API call with Axios, how to bind an onClick event with an API Call

I have one component, which is handle input component
import React, {useState} from 'react';
import FacebookApiCall from './Api'
export default function FacebookInterest () {
const [interest, setInterest] = useState('');
function HandleChange(event) {
setInterest(event.target.value);
}
return (
<div className="maincontainer">
<input className="searchbar" type="text" placeholder="Type an interest ..." value={interest} onChange={HandleChange}/>
<button onClick={() => FacebookApiCall(interest)} className="searchbutton">Search</button>
</div>
);
}
When a user click, i want to make a call to the API thanks to FacebookApiCall which is
import React, {useEffect} from 'react'
import axios from 'axios'
export default function FacebookApiCall(props) {
const url = `https://graph.facebook.com/search?type=adinterest&q=${props}&limit=10000&locale=en_US&access_token=EA`
useEffect(() => {
axios.get(url)
.then(res => {
console.log(url);
console.log(res);
//console.log(res.data.data[62].audience_size);
//console.log(res.data.data[62].name);
//console.log(res.data.data[62].description);
//console.log(res.data.data[62].path);
})
});
return (null);
}
the error returned by react is :
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
So I can't use a hooks inside my Facebook function i understand that now how can i make an api call without using useEffect and if I have to use useEffect no matter what, what i'm supposed to do ? I have to admit that im lost here.
Thanks a lot guys
So it looks like you're breaking one of the rules of hooks:
Only Call Hooks from React Functions
In your FacebookApiCall you're calling the useEffect hook from a non-react function.
The proper way to do this would be to do your api call from a function in your component.
import React, { useState, useEffect } from 'react';
function FacebookInterest () {
const url = `https://graph.facebook.com/search?type=adinterest&q=${props}&limit=10000&locale=en_US&access_token=EA`
const [interest, setInterest] = useState(null);
const [response, setResponse] = useState(null);
useEffect(() => {
// If you want do do some other action after
// the response is set do it here. This useEffect will only fire
// when response changes.
}, [response]); // Makes the useEffect dependent on response.
function callYourAPI() {
axios.get(url).then(res => {
// Handle Your response here.
// Likely you may want to set some state
setResponse(res);
});
};
function HandleChange(event) {
setInterest(event.target.value);
};
return (
<div className="maincontainer">
<input
className="searchbar"
type="text"
placeholder="Type an interest ..."
value={interest}
onChange={HandleChange}
/>
<button
onClick={() => callYourAPI(interest)}
className="searchbutton"
// You may want to disable your button until interest is set
disabled={interest === null}
>
Search
</button>
</div>
);
};

SWAPI request in React

I am trying to get SWAPI data from 'people' using react. I would ultimately like to retrieve the data and then set the people and create a card from the 10 people on page 1. When I console.log my response I am able to see the object returned. I am trying to set that using response.data.results (should contain people).
//full code:
import React, { useState, useEffect } from 'react';
import axios from "axios";
import Cards from "./components/Card"
function People() {
const [people, setPeople] = useState([]);
useEffect(() => {
axios.get('https://swapi.co/api/people/')
.then(res => {
//console.log(res);
setPeople(res.data.results)
})
.catch(err => {
console.log(`Data not received ${err}`)
})
}, [])
return (
<div className = "container">
{people.map((name, index) => {
return <Cards name={name} index={index}/>
})}
</div>
)
}
export default People;
When I console.log swPeople after using setswPeople I am returned an empty array.
Any ideas as to why the set is not giving me an array containing the 10 people on page one?
I see it working https://codesandbox.io/s/react-hooks-useeffect-frhmn
it take time to set the state , if we dont pass the second argument [] to useEffect you will see it is returning data correctly but that will cause the infinite loop , so we avoid that
import React, { useState, useEffect } from 'react';
import axios from "axios";
import Cards from "./components/Card"
function People() {
const [people, setPeople] = useState([]);
useEffect(() => {
axios.get('https://swapi.co/api/people/')
.then(res => {
//console.log(res);
setPeople(res.data.results)
})
.catch(err => {
console.log(`Data not received ${err}`)
})
}, [])
return (
<div className = "container">
{people.map((name, index) => {
return <Cards name={name} index={index}/>
})}
</div>
)
}
looks like this worked after all but it was taking close to 30s for me to see that info logged in console and I was being impatient
Have you tried to enter this url in your browser, https://swapi.co/api/people?
Because it seems the link is redirecting to another url while it needs to brign you back a JSON.
If you want to use SWAPI info replace you SWAPI to https://www.swapi.tech/api/people
it works well.
However I suggeust you to download the extension of JSONVue it will help you track your data with comfortable JSON view in your broweser.
And about the info of the 10 people you trying to get from SWAPI, when you'll open the browser with the new SWAPI adress, try to track the path you want to do in your code. You'll see the info you're trying to catch is leading to another API.

Cannot set data in variable after loading with useEffect()

So I am doing an online fullstack course for University of Helsinki and it is wanting me to use a weather and climate API to show information about the country and its current weather.
So I have three components: App, Lister, and Country. Inside App I make a useEffect call with axios to get the data for a list of countries. From there I want it so that when you click on the button or search it should show information about the country, including weather. To do that, when information about the specific country is shown, I have another useEffect call to an API for the weather. However, while the first API call seems to store the data on the list of countries, the second call does not.
I have tried changing the dependency of the second useEffect call to [name], but that also does not bring results, and when I just log the information with that type of dependency, I just see an infinite amount of calls in the console. Have tried with other API's just to see if I was miscalling it somehow but even those resulted in the same situation.
Inside the App component I do a call to get info about all the countries and it works fine.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import Lister from './Lister';
const App = () => {
const [places, setPlaces] = useState([]);
const [search, setSearch] = useState('');
const [results, setResults] = useState('');
useEffect(() => {
axios.get('https://restcountries.eu/rest/v2/all').then(r => setPlaces(r.data));
}, []);
.....
Everything works fine in here. I'm able to see and search and all that. I then have it call Lister which just maps the data from the country-search API into using the Country component.
.....
const listPlaces = () => {
if (results.length === 1) {
return (
<div>
{results.map(r => (
<Country
key={r.population / r.name.length + 5}
name={r.name}
capital={r.capital}
population={r.population}
languages={r.languages}
image={r.flag}
/>
))}
</div>
);
}
This is where the main crux of the issue is, in Country. When I call useeffect again, this time for the weather api, it doesn't seem to set it to the weather variable
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const Country = ({ name, capital, population, languages, image }) => {
const [weather, setWeather] = useState([]);
// have tried useState(), useState([]), useState({})
const accessKey = '';
useEffect(() => {
axios
.get(`http://api.weatherstack.com/...`)
.then(r => {
setWeather(r.data);
console.log(r.data);
});
}, []);
return (
<div>
<div className='Country'>
<h1>Name: {name}</h1>
<p>Capital: {capital}</p>
<p>Population: {population}</p>
<h2>Languages</h2>
<ul>
{languages.map(l => (
<li key={l.name.length}>{l.name}</li>
))}
</ul>
<img src={image} alt="Country's flag" height='100' width='100' />
</div>
<div className='Weather'>
<h1>Weather {weather.current.temperature} </h1>
<h2>Temperature </h2>
</div>
</div>
);
};
export default Country;
Weather will be of type undefined even though the log shows that the data was loaded, so should it not be set by the setWeather call?

Resources