ReactJS: Function run multiple times without being called - javascript

Is there any reason a function in a react component would run multiple times although it is being invoked only once?
I have this test function that auto-invokes itself as in:
let xfunction = (() =>
{
console.log('test');
}
)();
This is what I get in the console:
App.js Source Code:
import React, { useState, useEffect } from 'react';
import { getAllPokemons } from './services/pokemon'
import './App.css';
function App() {
const [pokemonData, setPokemonData] = useState([]);
const [loading, setLoading] = useState(true);
const initialUrl = 'payload.json'
useEffect(() => {
async function fetchData() {
let response = await getAllPokemons(initialUrl);
console.log(response);
await loadingPokemon(response.pokemon);
setLoading(false);
}
fetchData();
}, [])
const loadingPokemon = async (data) => {
let _pokemon = await Promise.all(data.map(async pokemon => {
return pokemon;
})
);
setPokemonData(_pokemon);
}
// Start - Filter by Pokemon Type
let pokemonTypes = (() =>
{
console.log('test');
}
)();
// End - Filter by Pokemon Type
return (
<div></div>
);
}
export default App;
The function is not being called or references anywhere else!
Thanks!

Solution as proposed by #Jared Smith:
If you do not want your functions rerendered and you are using react hooks, please include them in the useEffect hook as in:
useEffect(() => {
async function fetchData() {
let response = await getAllPokemons(initialUrl);
await loadingPokemon(response.pokemon);
setLoading(false);
}
fetchData();
includeFunctionHere();
}, [])

Related

Why is my function not dispatching in react component?

why is fetchReviews not fetching?
Originally didn't use fetchData in use effect.
Ive tried using useDispatch.
BusinessId is being passed into the star component.
no errors in console.
please let me know if theres other files you need to see.
thank you!
star component:
import React, { useState, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import {AiFillStar } from "react-icons/ai";
import { fetchReviews } from '../../actions/review_actions';
function Star(props) {
const [rating, setRating] = useState(null);
// const [reviews, setReview] = useState(props.reviews)
// const dispatch = useDispatch();
useEffect(() => {
const fetchData = async () => {
await fetchReviews(props.businessId)
};
fetchData();
console.log(props);
// getAverageRating();
});
const getAverageRating = () => {
let totalStars = 0;
props.reviews.forEach(review => {totalStars += review.rating});
let averageStars = Math.ceil(totalStars / props.reviews.length);
setRating(averageStars);
}
return (
<div className='star-rating-container'>
{Array(5).fill().map((_, i) => {
const ratingValue = i + 1;
return (
<div className='each-star' key={ratingValue}>
<AiFillStar
className='star'
color={ratingValue <= rating ? '#D32322' : '#E4E5E9'}
size={24} />
</div>
)
})}
</div>
);
};
export default Star;
star_container:
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import Star from "./star";
import { fetchReviews } from "../../actions/review_actions";
const mSTP = state => {
return {
reviews: Object.values(state.entities.reviews)
};
}
const mDTP = dispatch => {
return {
fetchReviews: businessId => dispatch(fetchReviews(businessId))
};
};
export default connect(mSTP, mDTP)(Star);
console image
why is fetchReviews not fetching? Originally didn't use fetchData in use effect. Ive tried using useDispatch. BusinessId is being passed into the star component. no errors in console.
edit!***
made some changes and added useDispatch. now it wont stop running. its constantly fetching.
function Star(props) {
const [rating, setRating] = useState(null);
const [reviews, setReview] = useState(null)
const dispatch = useDispatch();
useEffect(() => {
const fetchData = async () => {
const data = await dispatch(fetchReviews(props.businessId))
setReview(data);
};
fetchData();
// console.log(props);
// getAverageRating();
}), [];
ended up just calling using the ajax call in the useEffect.
useEffect(() => {
const fetchReviews = (businessId) =>
$.ajax({
method: "GET",
url: `/api/businesses/${businessId}/reviews`,
});
fetchReviews(props.businessId).then((reviews) => getAverageRating(reviews));
}), [];
if anyone knows how i can clean up and use the dispatch lmk.
ty all.
useEffect(() => {
const fetchData = async () => {
const data = await dispatch(fetchReviews(props.businessId))
setReview(data);
};
fetchData();
// console.log(props);
// getAverageRating();
}), [];
dependency array is outside the useEffect. Since useEffect has no dependency option passed, function inside useEffect will run in every render and in each render you keep dispatching action which changes the store which rerenders the component since it rerenders code inside useEffect runs
// pass the dependency array in correct place
useEffect(() => {
const fetchData = async () => {
const data = await dispatch(fetchReviews(props.businessId))
setReview(data);
};
fetchData();
// console.log(props);
// getAverageRating();
},[]), ;
Passing empty array [] means, code inside useEffect will run only once before your component mounted

useEffect hook wont run codeblock

My useEffect hook dont seem to be running the block of code within its scope. Not exactly sure why, when i debug it the useEffect hook gets hit but the code within it never runs. I have placed a break point and it never lands on it.
import {useState, useEffect} from "react";
const useApiResult = (request) => {
const [results, setResults] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
loadData(request);
}, [request]);
const loadData = async (request) => {
console.log(request)
try
{
const response = await fetch(request);
if(response.ok) {
setResults(await response.json());
setError(null);
} else {
setError(await response.text());
}
}
catch (err) {
setError(err);
}
}
return [results, error];
};
export default useApiResult;
Where I call useApiResult
import { useMemo } from 'react';
import { getPokemons } from '../requests';
import useApiResult from '../customHooks/useApiResults';
const usePokemons = () => {
const request = useMemo(() => getPokemons(), []);
return useApiResult(request);
}
export default usePokemons;
getpokemons.js
export const BASE_URL = "https://pokeapi.co/api/v2";
const createUrl = (base, path) => `${base}${path}`;
export const getPokemons = () => [
createUrl(BASE_URL, "/pokemon?offset=300&limit=10"),
{
method: "GET",
}
];
My steps to catch issue:
When I looked in your sandbox I noticed error: results is null
I also found const [results, error] = usePokemons(); in PokemonList component, so I thought that this error is not necessary, I just removed it. Because you never used it in component.
I still got results is null I just add condition render via &&. It looks like:
results &&
results.map((key, i) => (
I got new error: results.map is not a function. It means that results is not array. When I saw at results I noticed that it has inside array with the same name. So I just add resuts after a dot.
results &&
results.results.map((key, i) => (
Here we go:)

"Promise{<pending>}" in console instead of a value

I am trying to import a function that fetches data from an api in a file (.src/api/index.js) to my App.js (.src/App.js).
.src/api/index.js
import axios from 'axios';
const url = 'https://covid19.mathdro.id/api';
export const fetchData = async () => {
try {
const res = await axios.get(url);
return res;
} catch (error) {}
};
.src/App.js
import React, { useEffect } from 'react';
import { fetchData } from './api';
const App = () => {
useEffect(() => {
const data = fetchData();
console.log(data);
}, []);
return <div></div>;
};
export default App;
};
I am getting a Promise{<pending>} in my console when I run this but I am trying to get the values in the object.
fetchData() is an async function, and you need to await it like so:
const data = await fetchData();
Then, the useEffect must also be an async function:
useEffect(async () => {
const data = await fetchData();
console.log(data);
}, []);
You are not waiting for promise to resolve. use await or .then. If you wanna use await, make callback function of useEffect async function.
const App = () => {
useEffect(async () => {
const data = await fetchData();
console.log(data);
}, []);
return <div></div>;
};
Other approach is to use .then.
const App = () => {
useEffect(async () => {
const data = fetchData().then((data) => console.log(data));
}, []);
return <div></div>;
};

Unable to copy array using setstate hook

I am fetching data from backend using axios whenever I am trying to update hooks it is not updating.
The data is JSON from where I am extracting data and trying to set element. It might sound silly but can somebody tell me what is dependent array?
I keep getting this
Line 18: React Hook useEffect has a missing dependency: 'elements'. Either include it or remove the dependency array react-hooks/exhaustive-deps
Here is code
import React, { useEffect, useState } from 'react';
import './App.css';
import axios from 'axios';
function App() {
const [elements, setElements] = useState([]);
useEffect(() => {
const res = async () => {
const result = await axios.get('/data');
const data = result.data;
console.log(data);
setElements(elements => [...elements, data]);
console.log(elements);
};
res();
}, []);
console.log(elements.map(element => console.log(element)));
return <div className='App'>Hello</div>;
}
export default App;
Just console.log outside your effect. You're already using the updater version of useState
setElements(elements => [...elements, data])
The missing dependecy warning is coming from console.log(elements)
import React, { useEffect, useState } from 'react';
import './App.css';
import axios from 'axios';
function App() {
const [elements, setElements] = useState([]);
useEffect(() => {
const res = async () => {
const result = await axios.get('/data');
const data = result.data;
console.log(data);
setElements(elements => [...elements, data]);
};
res();
}, []);
console.log(elements);
return <div className='App'>Hello</div>;
}
export default App;
Missing dependency warning is because you use console.log(elements) inside the useEffect.
And your elements log is not showing latest result because state is not changed (yet)
Just add a useEffect to keep track of elements changes like below.
function App() {
const [elements, setElements] = useState([]);
useEffect(() => {
const res = async () => {
const result = await axios.get('/data');
const data = result.data;
console.log(data);
setElements(elements => [...elements, data]);
};
res();
}, []);
useEffect(() => console.log(elements), [elements])
return <div className='App'>Hello</div>;
}
export default App;
To answer your question;
The dependency array is their to let React know when the useEffect in this case should be triggered. So the useEffect i added, only triggers when its dependency elements is changed.
In your case you are puting the array data inside elements, setElements(elements => [...elements, data]); so it will be array inside array.
Try the below :
function App() {
const [elements, setElements] = useState([]);
useEffect(() => {
const res = async () => {
const result = await axios.get('/data');
const data = result.data;
console.log(data);
setElements([...elements, data]);
};
res();
}, []);
useEffect(() => console.log(elements), [elements])
return <div className='App'>Hello</div>;
}
export default App;

How to fire the function useEffect after clicking event?

Recently am learning React hooks and am now doing a search app which have to call API then return the list movies correspond to what i type in the search box.
My code here:
useFetch.js
import { useState, useEffect } from 'react'
export const useFetch = (url, initialState) => {
const [data, setData] = useState(initialState)
const [loading, setLoading] = useState(true)
useEffect(() => {
async function fetchMovies() {
const response = await fetch(url)
const data = await response.json()
setData(data.Search)
setLoading(false)
}
fetchMovies()
}, [url])
return { data, loading }
}
App.js
import React, { useState } from 'react'
import Search from './components/Search'
import Result from './components/Result'
import Loading from './components/Loading'
import { useFetch } from './utils/useFetch'
export default function App() {
const [key, setKey] = useState('Iron man')
const onSearch = (key) => {
setKey(key)
}
const {data, loading} = useFetch(`https://www.omdbapi.com/?s=${key}&apikey=${API_KEY}`)
return (
<>
<Search handleSearch={onSearch}/>
<Loading isLoading={loading} />
<Result movies={data}/>
</>
)
}
As far as i understand after clicking button search function call API will be fired and return the result as expect. I can't put
const {data, loading} = useFetch(`https://www.omdbapi.com/?s=${key}&apikey=${API_KEY}`)
inside onSearch function. Follow the code function call API is automatically called whenever the app start and return undefined as result.
Can anyone help me out and explain why?
You are correct in your understanding of how hooks can only be called at the top level in a react component. Make the following changes and the API won't get called the first time around but will get called subsequently.
Use url state variable and extract generateUrl logic outside the component:
function generateUrl(key) {
return `https://www.omdbapi.com/?s=${key}&apikey=${API_KEY}`
}
function MyComponent() {
const [url, setUrl] = React.useState('');
//...
}
Check for url presence in useFetch hook by wrapping fetchMovies() call in an if condition. This way, API won't trigger since default value of url is empty.
import { useState, useEffect } from 'react'
export const useFetch = (url, initialState) => {
const [data, setData] = useState(initialState)
const [loading, setLoading] = useState(true)
useEffect(() => {
async function fetchMovies() {
const response = await fetch(url)
const data = await response.json()
setData(data.Search)
setLoading(false)
}
if(url) {
fetchMovies()
}
}, [url])
return { data, loading }
}
Finally, modify onSearch
const onSearch = (key) => {
setUrl(generateUrl(key))
}
Perhaps you could expose setUrl through something like:
return { data, loading, onSearch: (key) => setUrl(generateUrl(key)) }

Categories