What I am trying to do?
I am trying to call an api that sends information and I want to render the information on to the react app. I have acheived what I wanted to however, there is a problem.
THE PROBLEM
React is firing unlimited request to the api as shown in the image below.
app.js
import React, { useState } from 'react';
import './css/main.css'
const App = () => {
const [data, setData] = useState([]);
fetch(`http://localhost/api/index.php`).then((res)=>{return res.json()}).then(
(data)=>{
setData(data)
}
)
return (
<div>
{data.length > 0 && (
<ul>
{data.map(ad => (
<li key={info.id}>
<h3>{info.name}</h3>
<p>{info.details}</p>
</li>
))}
</ul>
)}
</div>
);
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<App />,
document.getElementById('root')
);
Why is it not working?
The reason why this happens is that you are fetching data and update state on the fly that causing component to rerender, then to fetch data again, set state, rerender (getting stuck in a loop).
How to solve?
You should use useEffect hook (read more here). Also, you can read more about data fetching on official documentation website here.
What will change in your code?
The whole fetch will be wrapped in a useEffect hook.
useEffect(() => {
fetch(`http://localhost/api/index.php`).then((res)=>{return res.json()}).then(
(data)=>{
setData(data)
}
)
}, []);
you need to use useEffect(). The problem is when you set the data your component rendering from scratch and again fetching data and again setting and again again...
useEffect(() => {
fetch(`http://localhost/api/index.php`)
.then(res=>res.json())
.then(data=>setData(data))
}, []);
This is because you are setting the state in the API response itself and state change triggers re-render.
This happens as follows: fetch API call -> Data response -> set state -> trigger re-render -> fetch API call and the cycle continuous and result in infinite API call.
Solution: Call the API inside useEffect, useEffect is a hook that triggers once when the page renders or when its dependency changes.
Update your app.js as follows:
import React, { useState } from 'react';
import './css/main.css'
const App = () => {
const [data, setData] = useState([]);
useEffect(()=> {
fetch(`http://localhost/api/index.php`).then((res)=>{return res.json()}).then(
(data)=>{
setData(data)
}
),[]
}
return (
<div>
{data.length > 0 && (
<ul>
{data.map(ad => (
<li key={info.id}>
<h3>{info.name}</h3>
<p>{info.details}</p>
</li>
))}
</ul>
)}
</div>
);
}
export default App;
Put fetch function inside useEffect and inside dependency array define when you want to run it. It will stop React from firing unlimited requests.
React calls the body of your component function on each render. In your case you:
Perform a request,
Upon completing the request, you set the state of your useState hook,
The state triggers a re-render,
The cycle repeats.
So the solution is to use 'life cycles' by using something like useEffect, in which you can determine when to run your callback (the fetch() in your case) - only on mounting the component, or when props change.
const renderData = () => {
fetch(`http://localhost/api/index.php`).then((res)=>{return res.json()}).then(
(data)=>{
setData(data)
}
}
useEffect(() => {
renderData();
},[]);
Related
i have a react component thats keep re-rendering idk why but i think the reason is the data fetching
data code :
export function KPI_Stock_Utilisation() {
const [kpi_stock_utilisation, setKpi_stock_utilisation] = useState([{}]);
useEffect(() => {
axios.get("http://localhost:5137/KPI_Stock_Utilisation").then((response) => {
setKpi_stock_utilisation((existingData) => {
return response.data;
});
});
}, []);
console.log('data get')
return kpi_stock_utilisation;
}
this log displayed many times , and the log in the component too
component code :
import React from "react";
import { KPI_Stock_Utilisation } from "../../Data/data";
import { useEffect } from "react";
export default function WarehouseUtilisChart(props) {
let kpi_stock_utilisations =KPI_Stock_Utilisation();
let Stock_utilisation = (kpi_stock_utilisations.length / 402) * 100;
console.log('component render')
return (
<div>
<p>{kpi_stock_utilisations}</p>
</div>
);
}
im new with react i tried useEffect inside the componenets but its not working
Calling the react custom hook KPI_Stock_Utilisation several times will for sure render more than once.
in your case I suggest you use useEffect in the same component as I will show you.
import React,{useEffect,useRef} from "react";
import { KPI_Stock_Utilisation } from "../../Data/data";
import axios from 'axios';
export default function WarehouseUtilisChart(props) {
const [kpi_stock_utilisation, setKpi_stock_utilisation] = useState([{}]);
const stock_utilisation= useRef(0);
useEffect(() => {
axios.get("http://localhost:5137/KPI_Stock_Utilisation").then((response) => {
stock_utilisation.current = (response.data.length / 402) * 100;
setKpi_stock_utilisation(response.data);
});
//this will guarantee that the api will be called only once
}, []);
//you should see this twice, one with the value 0, and another one, the calculated data
console.log('component render',stock_utilisation.current)
return (
<div>
<p>{kpi_stock_utilisations}</p>
</div>
);
}
To note, if you call this component from more than one location, for sure it will render several times - keep that in mind.
On the other hand, all your variables should always start with a lower case and try to name your variables like this: instead of kpi_stock_utilisation change it to kpiStockUtilisation for a better coding practice
You got into infinite loop.
Its hard to explain why it doesn't work as expected, but I can try.
First of all, useEffect with empty array of dependencies works like componentDidMount and fires only after (!) first render.
So you have some value returned from your let kpi_stock_utilisations =KPI_Stock_Utilisation(); then it rendered, after this your useEffect fires a request and set state, setting of state trigger re-render and new value to return, this new value trigger your parent component to return let kpi_stock_utilisations =KPI_Stock_Utilisation(); might run again.
If you are trying to create a custom hook for fetching some info, follow rules of hooks
I hope it helped you
I am creating this simple news app with dotnet webapi and react. I want to fetch the news from my backend. The API is working fine, I have tested it, but somehow my useEffect won't run and I can't fetch the data. What am I doing wrong and what is the proper way of doing this? Any help will be appreciated!
Here's my app.js where the fetching should be working.
import './App.css';
import axios from 'axios';
import ArticleList from './/components/ArticleList.jsx';
function App() {
const [articles, setArticles] = useState(null)
useEffect(() => {
console.log('If it works, this should be shown!')
axios.get('https://localhost:7112/News').then(response => {
setArticles(response.data)
console.log(articles)
});
},[]);
return (
<div className="App">
<ArticleList articles={articles}/>
</div>
);
}
export default App;
import ArticleListItem from './ArticleListItem.jsx'
export default function ArticleList(articles) {
return (
<>
{articles && articles.map(article => (<ArticleListItem key={article.title} article={article} />
))}
</>
)
}
There's the component which throws error: articles.map is not a function.
The error does not come from useEffect neither tha App component . But ArticleList it self when you pass articles as a props to ArticleList component and before mapping it you have to check if you have articles first :
You can do something like this :
{props.articles && props.articles.map(...)
You need to check articles to render Loading or ArticleList
{articles && <ArticleList articles={articles}/>}
or you set initial value for articles state:
const [articles, setArticles] = useState([])
In my case, I was using webstorm and for some reason it was not printing the useEffect console logs in my webstorm terminal, when I checked the logs in the browser console everything was getting printed in the logs
Im new in react.
I'm Created two file App.js and UseEffect.js
I'm Learn about lifecycle in react with function.
So When I See in console, that's render multiple time.
You can see my picture below.
My Console In Browser
This Is My Code
UseEffect.js
import React, {useState, useEffect} from "react";
function MyFunction(){
console.log('-> Function Init')
const [count, setCount] = useState(0)
const handleCount = () => {
setCount(prevState => {
return prevState+1
})
}
//LifeCycle
useEffect(() => {
console.log('my first effect')
})
console.log(`-> Start Render (${count})`)
return(
<div>
<h1>Function Component</h1>
<p>
<button onClick={handleCount}>Count</button>
{count}
</p>
</div>
)}
export default MyFunction
App.Js
import './App.css';
import UseEffect from './components/UseEffect'
function App() {
return (
<div className="App">
<UseEffect />
</div>
);
}
export default App;
How do it's work?, I Want it. it's just render one times.
Your useEffect call is missing a dependency array. When you want it to run only at the initial render, you need to pass it an empty array as its dependencies.
useEffect(() => {
console.log('my first effect')
}, [])
For further details, see this question.
Why it renders twice:
It's an intentional feature of the StrictMode. This only happens in development, and helps find accidental side effects put into the render phase. We only do this for components with Hooks because those are more likely to accidentally have side effects in the wrong place.
-gaearon
TLDR: It's a feature not a bug.
I have a rails (7.0.2) application and just installed React. I'm very new to react and can't seem to understand why it looks like my component is loading multiple times, the first time with an empty value for props and the second time with the correct values for props.
App.js:
import "./App.css";
import axios from "axios";
import Customers from "./components/customers";
import { useEffect, useState } from "react";
const API_URL = "http://localhost:3000/internal_api/v1/customers";
function getAPIData() {
return axios.get(API_URL).then((response) => response.data);
}
function App() {
const [customers, setCustomers] = useState([]);
useEffect(() => {
let mounted = true;
getAPIData().then((items) => {
if (mounted) {
setCustomers(items);
}
});
return () => (mounted = false);
}, []);
console.log('LOADED App.js');
return (
<div className="App">
<h1>Hello</h1>
<Customers customers={customers} />
</div>
);
}
export default App;
and customers.js:
import React from "react";
function Customers(props) {
console.log('LOADED customers.js');
return (
<div>
<h1>These customers are from the API</h1>
{props.customers.data.map((customer) => {
return (
<div key={customer.id}>
<h2>{customer.id}</h2>
</div>
);
})}
</div>
);
}
export default Customers;
When I remove this part of the code and reload the page, my props come through correctly when looking in console. Then, when I put the code back and save (without reloading), it displays correctly.
{props.customers.data.map((customer) => {
return (
<div key={customer.id}>
<h2>{customer.id}</h2>
</div>
);
However, as soon as I reload again, I get the same following error:
Uncaught TypeError: Cannot read properties of undefined (reading 'map')
It seems as though the first time everything renders, props is empty. Then the second time, it is full with the data. I checked my rails app and it only hits the API once. What am I doing wrong?
More log outputs:
React component rendering multiple times?
React will render fast before completing the request in use Effect
so in first render customers array will be empty
when request is fulfilled, you are changing state, So react will re-render the component
Only component that uses state reloads when the state is changed this is required else UI will not update
failing when reloading the page? | Failed on Initial Load
Since in Initial render customers will have no data customers.data will be undefined so it will not have map
to bypass this error use props.customers?.data && props.customers.data?.map() addding question mark means expression will be evaluated if not undefined
Source - Optional_chaining
import React from 'react'
import axios from "axios"
import { useEffect } from "react"
import { useState } from "react"
export function Profile (){
const pathname = window.location.pathname
const[data,setData] = useState([])
const [loaded,hasloaded] = useState(false)
let username = pathname.split("/")[1]
useEffect(()=>{
axios.post('http://localhost:5000/profile/getProfile', {
"username":username
})
.then((res)=> setData(res.data))
})
return (
<div className='Wrapper'>
<img/>
{loaded ? <h2>{data[0].username}</h2>:<h2>Loading</h2>}
<img />
</div>
)
}
axios it taking like 10 seconds to get the response is this normal? when i request on postman it takes like 1 second. also how can i render when i have recieved the data without causing to many rerenders?
When the dependency array for useEffect is undefined (instead of an empty array) then the effect runs on every render. And within your useEffect you are updating state, which will trigger a re-render. This means every render triggers a re-render.
It looks like you only want the effect to run once, when the component first loads. For that, pass an empty dependency array to useEffect:
useEffect(()=>{
axios.post('http://localhost:5000/profile/getProfile', {
"username":username
})
.then((res)=> setData(res.data))
}, []); // <--- here