Unable to copy array using setstate hook - javascript

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;

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

How to fetch API as soon as page is loaded in React?

Whenever I visit a page it should automatically fetch the API
import React from 'react'
const Component = () => {
fetch("api url").then((res) => console.log(res))
return (
<div>comp</div>
)
}
export default Component
It is very simple using react hook use effect please learn basics of useffect hook on react docs or any youtube tutorial and as for the answer
import React, { useEffect } from 'react'
const comp = () => {
useEffect(() => {
fetch("api url").then((res)=>console.log(res))
}, [])
return (
<div>comp</div>
)
}
export default comp
here empty dependency means every time page loads only once
use the useEffect for this.
The useEffect method will execute the passed callback on the mount of the component and on every time one of the dependency array parameters is changed. therefore:
const Comp = () => {
useEffect(() => {
fetch("api url").then((res)=>console.log(res))
}, []);
return (
<div>comp</div>
)
}
Will make the callback to fire only once (because the empty dependency array) on the component mount.
You should use the useEffect Hook in your principal component like app.js
import React, {useEffect} from 'react'
useEffect(() => {
fetch("api url").then((res)=>console.log(res))
}, []);
Be careful, this manipulation can consume a lot of resources (a lot of data to fetch etc.)
Thery
import React, { useState, useEffect } from 'react'
const Comp = () => {
const [ data, setData ] = useState([]);
const getData = async () => {
const res = await fetch("api url");
const data = await res.json();
setData(data)
}
useEffect(()=>{ getData() },[]);
return (
<>
<div>comp</div>
// dispaly your data here from data state
</>
)
}
export default Comp;
Fetch and use data with useState
const initialValue = {};
const comp = () => {
const [data, setData] = useState(initialValue);
useEffect(() => {
let ignore = false;
const fetchData = async () => {
const res = fetch("api url");
if (ignore) { return; }
setData(res.json())
return () => {
ignore = true;
}
}
, [])
return (
<div>comp {data.prop}</div>
)
}
More on working with state
More about useEffect life cycle
Hope it helps
You don't need to use the API function like this, it will be called continuously, you need to use useEffect hook, when your component reloads useEffect will be called, and you can learn about the useEffect dependency here,
import React, { useEffect, useState } from 'react'
const comp = () => {
const [data, setData] = useState([]);
useEffect(() => {
fetch("api url").then((res)=> {
console.log(res)
setData(res)
} )
}, [])
return (
// use data state to show the data here
<div>comp</div>
)
}
export default comp;

How can I update state after setting it in UseEffect?

I want to display a list of products in one of my components. I need to use UseEffect to get the results of a function that returns a promise. I then am setting state in UseEffect but am having trouble displaying the products. The state is getting updated but I am not able to render the results on the dom.
Here's the component:
import React, { useEffect, useState } from "react"
import styled from "styled-components"
import pullShopifyData from "../../functions/shopify"
export default function DataPreview(props)
const { apiKey } = props
const [data, setData] = useState([])
useEffect(() => {
pullShopifyData(apiKey).then(response => {
console.log(response.data.shop.products)
setData(response.data.shop.products)
})
}, [])
return (
<Wrapper>
{data.length > 0 ? data.map(product => (
<ProductWrapper>{product}</ProductWrapper>
)): <NoProductsWrapper>No Products Found</NoProductsWrapper>}
</Wrapper>
)
}
const Wrapper = styled.div``
const ProductWrapper = styled.div``
const NoProductsWrapper = styled.div``
Here's the output on the dom:
Move your data fetch function in to async wrapper function. Then just call it in useEffect.
useEffect(() => {
fetchSomething();
}, [])
const fetchSomething = async () => {
const response = await pullShopifyData(apiKey);
console.log(response.data.shop.products)
setData(response.data.shop.products)
}

ReactJS: Function run multiple times without being called

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

Using .map() with useEffect and Api

I am trying to use the useEffect to grab some data from an API. I am succesful in grabbing the data but after I set my state and try to map through it I just get "Can't read map of undefined". I think the problem is that it's running my .map() code before it gets the response. i am just unsure of how to solve this
This is the api response:
data: {count: 87, next: "https://swapi.co/api/people/?page=2", previous: null, results: Array(10)}
Here is my code
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './App.css';
import CharacterMap from './characterMap'
const App = () => {
let [getChars, setChars] = useState(0);
useEffect(() => {
axios.get(`https://swapi.co/api/people/`)
.then(res => setChars(res) )
},[]);
console.log(getChars.data.map((e) => e))
return (
<div className="App">
<CharacterMap info={getChars} />
</div>
);
}
export default App;
axios.get is an async function and you are trying to get the data outside of an async function which is no completed yet.
You could use useEffect with dependency array which is equal to componentDidUpdate to get the data.
Initialized the state with the same datatype that you expect, in this case we expect an array you initialized ith with empty array.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './App.css';
import CharacterMap from './characterMap'
const App = () => {
let [chars, setChars] = useState([]);
useEffect(async () => {
try{
let response = await axios.get(`https://swapi.co/api/people/`)
let data = await response.json();
setChars(data);
} catch(error) {
console.error(error.message);
}
},[]);
// If you want to access the updated state then use this.
useEffect(() => {
let newState = chars.map((e) => e); // map your state here
setChars(newState); // and then update the state
console.log(newState);
},[getChars]);
return (
<div className="App">
<CharacterMap info={chars} />
</div>
);
}
export default App;
The second useEffect hook trigger on each state update and so you can get the updated state here.
It will also trigger a re-render so you can also use the map in return statement;
Or you could update the data on axios response and then set the state. Recommended
useEffect(async () => {
try{
let response = await axios.get(`https://swapi.co/api/people/`)
let data = await response.json();
let newState = data.map((e) => e); // map your state here
setChars(newState); // and then update the state
console.log(newState);
} catch(error) {
console.error(error.message);
}
},[]);
Keep the default values as array
let [getChars, setChars] = useState([]);
you are setting data to array chars. instead of that set array(results) that you are getting in response.
As you defined let [getChars, setChars] = useState([]);
useEffect(async () => {
axios
.get(`https://swapi.co/api/people/`)
.then(res=> setChars(res.data.results))
.catch(err=> console.log(err))
},[]);

Categories