How do I call an Axios response once and without a button - javascript

I am new to using react and Axios and I have created a get request, I can call it once with a button, however I don't want this button and instead want information to be displayed when the page loads/with the page so the user can see it straight away. But when calling my function once it gets called continuously and crashes the web browser and I don't understand why this is happening I have googled and I couldn't find anything. Here is the code that gets ran.
kitchen.js
import React from 'react';
import { Container } from 'react-bootstrap';
// import Axios from 'axios';
import { Link } from 'react-router-dom';
import GetFood from './getFood';
export default function Kitchen() {
return(
<Container>
<div>
<h1>This is the kitchen portal</h1>
<Link to='/gettingfood'><button>Get Food</button></Link>
<Link to="/addingfood"><button>Add food</button></Link>
<Link to="/deletefood"><button>Delete Food</button></Link>
</div>
<GetFood/>
</Container>
);
}
GetFood.js
import React, { useState } from 'react';
import Axios from 'axios';
export default function GetFood() {
const [responseData, setResponseData] = useState([])
// fetches data
async function fetchData(){
await Axios.get("http://localhost:3001/getfood").then((response)=>{
setResponseData(response.data);
console.log(response.data);
alert("Information received!")
})
.catch((error) => {
console.log(error)
})
}
fetchData();
return (
<div>
<button onClick={fetchData}>Get</button>
{responseData.map((val,key)=>{
return (
<div>
<div id="data">
<p>Item:{val.item}</p>
<p>Price:{val.price}</p>
</div>
</div>
)
})}
</div>
)
}

In React, functional components get called everytime they get rendered.
To create side-effects, like requesting data from an external source, you should use the useEffect hook.
This hook takes a function to execute and a dependency array, which defines when the supplied function gets called.
If you specify an empty array, the function only gets called on the first render cycle.
If you specify any variables, the function gets called on the first render cycle and when any of the specified variables change.
This should go instead of your call to fetchData():
useEffect(() => {
fetchData();
}, []);

Related

unable to map as url is not an array // React Router

Hi I have a main page called FeaturedProduct.js which lists all the products fetch from the API https://fakestoreapi.com.
I trying to set up react router dom version (6) whereby user click on any of the product will open up that single product through Product.js
This is my code: https://codesandbox.io/s/magical-smoke-r7yik9?file=/src/Product.js
I having issues because I can't use the map function without errors.
The error being `data.map' is a not a function (in Product.js)
Do I need to access further into the "api" json like data.x.map?
Always check carefully the response you are getting from an api weather its object or an array.
i have modified your file, you can replace it with your original product.js component.
And always use ?. operator whenever you play with data that come from an api because useEffect hook will run after your component is loaded, hence it will give you an error that your data is undefined. It will not happen in your case you are getting only single object which is fast operation, but if you are getting larger data then you have to use ?. operator.
import React, { useState, useEffect } from "react";
import { Link, useParams } from "react-router-dom";
import axios from "axios";
// individual product
// functional component
const Product = () => {
const [data, setData] = useState('');
const { id } = useParams();
useEffect(() => {
axios
.get(`https://fakestoreapi.com/products/${id}`) // change from ?id=${id} to ${id} because API url is .com/products/1 // But couldn't map due to not being array
.then((res) => {
setData(res.data);
})
.catch((err) => console.log(err));
}, []);
return (
<div>
<div className="product-container" key={data?.id}>
<div>
<img className="prod-image" src={data?.image} alt="" />
</div>
<div>
<h1 className="brand">{data?.title}</h1>
<h2>{data?.category}</h2>
<p>{data?.description}</p>
<p>
<strong>Price:</strong> {data?.price}
</p>
<p>
<strong>Rating:</strong> {data?.rating?.rate}
</p>
</div>
</div>
<div className="back">
<Link to="/">Feature Products</Link>
</div>
</div>
);
};
export default Product;

React firing unlimited requests

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();
},[]);

React Query resends request after unfocusing React TinyMCE

Recently I've tried to create my own component using React Query with TinyMCE for React, but I noticed that every time I loose focus from TinyMCE editor's text area my request from React Query is sent again even though nothing has changed in my components (at least I think there is no need for rerender of the component).
Here you can see that every time I click into editor and after that outside of the editor the request is sent
I created project to simulate the problem. You can see that every time you focus and unfocus from the text area of the TinyMCE editor the request from React Query is sent. I tried to use useEffect to know if the provided callback is called multiple times as well, but the useEffect works as expected.
import React, { useEffect } from "react";
import {
QueryClient,
QueryClientProvider,
useQuery
} from "#tanstack/react-query";
import ReactDOM from "react-dom/client";
import { Editor } from "#tinymce/tinymce-react";
export default function MyEditor() {
return (
<div>
<Editor />
</div>
);
}
const fetchData = async () => {
console.log("Fetching data", new Date());
return await fetch("https://jsonplaceholder.typicode.com/posts/1").then((d) =>
d.json()
);
};
function App() {
useQuery(["api"], fetchData);
useEffect(() => {
console.log("This is going to be logged only once");
}, []);
return (
<form>
<h1>My editor</h1>
<MyEditor />
</form>
);
}
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById("container")).render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
These are my package versions:
{
"dependencies": {
"#tanstack/react-query": "4.3.9",
"#tinymce/tinymce-react": "4.2.0",
"react": "18.2.0",
"react-dom": "18.2.0"
}
}
I think it's because the editor renders an iframe, you can use the refetchOnWindowFocus option to avoid refetching:
useQuery(["api"], fetchData, { refetchOnWindowFocus: false })
or perhaps using the method to ignore iframe focus described in the same doc page
It works on codesandbox

Why My React Component Render Multiple Times In Console?

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.

React component rendering multiple times, failing when reloading the page

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

Categories

Resources