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
Related
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();
},[]);
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
This question already has answers here:
The useState set method is not reflecting a change immediately
(15 answers)
Closed 1 year ago.
I've posted something similar in the past and never really got an answer and I keep running into this problem. Things in my app are working, but I'm not really sure why. I'm using a third-party api to make a simple recipe app. The data I'm passing into my component is displaying as expected, but it's not logging into the console as expected.
Line 20 of App.js is logging what I'd expect (the data received from the api).
Line 4 of Recipe.jsx is logging what I'd expect (each item in the recipes array).
But line 22 of App.js is coming back as undefined. I would expect that because I setRecipes to 'data', that 'recipes' would log the same as 'data'. Can anyone explain this to me?
import React, { useEffect, useState } from "react";
import "./App.css";
import Recipe from "./Recipe";
import axios from "axios";
function App() {
const APP_ID = "XXXXXXXX";
const APP_KEY = "XXXXXXXXXXXXXXXXXXX";
const url = `https://api.edamam.com/api/recipes/v2?type=public&q=chicken&app_id=${APP_ID}&app_key=${APP_KEY}`;
const [recipes, setRecipes] = useState([]);
useEffect(() => {
getRecipes();
}, []);
const getRecipes = async () => {
const res = await axios(url);
const data = await res.data.hits;
console.log(data);
setRecipes(data);
console.log(recipes);
};
return (
<div className="App">
<form className="search-form">
<input className="search-input" type="text" />
<button className="search-button" type="submit">
Search Recipes
</button>
</form>
{recipes &&
recipes.map((recipe, idX) => <Recipe recipe={recipe} id={idX} />)}
</div>
);
}
export default App;
import React from "react";
const Recipe = ({ recipe, id }) => {
console.log(recipe);
return (
<div key={id}>
<h1>{recipe.recipe.label}</h1>
<p>{recipe.recipe.calories}</p>
<img src={recipe.recipe.images.SMALL.url} alt="" />
</div>
);
};
export default Recipe;
SetState is asynchronous and may not resolve straightaway. See this part of the docs for more information
https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
As you've said, the data coming back is correct, and you've made a call to set state. But the state hasn't resolved by the time you come to the next line where state is consoled out
I have returned json response from getStaticProps and console logged it in getStaticProps to verify correct json response. So, fetch is working fine and I am getting correct response from API.
import Layout from '../components/layout';
import fetch from 'isomorphic-unfetch';
const Index = ({data}) => {
console.log(data)
return (
<Layout>
<div>
<h1>Welcome to Next Application</h1>
<h3>Users List</h3>
{data ?
data.map((item, i) => {
return (
<li key={i}>{item.name}</li>
)
}):
<span>Loading...</span>
}
</div>
</Layout>
);
}
export const getStaticProps = async () => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users`);
const data = await response.json();
console.log(data);
return {
props:{
data
}
}
}
export default Index;
Getting data as undefined in Index component.
What am I missing ?
My Output - https://ibb.co/Ns9143C
Github - https://github.com/ho-dor/next-poc
The problem is in your custom App file, if your remove your custom App wrapper your problem will solve but if you want to keep custom app wrapper just update your _app.js like this:
import App from 'next/app';
const MyApp = ({ Component, props }) => {
return (
<div className="MyApp">
<p>_app.js file</p>
<Component {...props} />
</div>
);
};
MyApp.getInitialProps = async (appContext) => {
// calls page's `getInitialProps` and fills `appProps.pageProps`
const appProps = await App.getInitialProps(appContext);
return { ...appProps };
};
export default App;
For more info check here: Custom App - NextJS
getStaticProps (Static Generation): Fetch data at build time.
Maybe you could try to rebuild your app to see if it works.
You are using custom _app component in your source code. If you're using custom _app component, you need to check if the components have static components and trigger that manually.
This will be done in custom app component itself.
If you're not using it, then you won't face any issue.
You can follow this approach I used for getInitialProps in my custom _app here