useEffect is not working in functional component,showing null data - javascript

UseEffecct is not getting the data from the API,it is showing null when I try to console........................................
import React, { useEffect, useState } from "react";
import axios from "axios";
export default function footerAjax() {
const [data, setData1] = useState('');
useEffect(async () => {
console.log("inerrrr");
axios
.get('https://jsonplaceholder.typicode.com/todos')
.then((res) => {
console.log("api --"+JSON.stringify(res.data));
setData1(res.data);
});
},[]);
return (
<div className="app">
{console.log("footer == "+JSON.stringify(data??{}))}
<FooterBody footerData={data??{}} />
</div>
);
}

In your api does returns only array of objects. so it doesnot have key called data its becoming undefined. just remove data key it should work.
console.log("api --"+JSON.stringify(res));
setData1(res);
hope this helps!!

I can see multiple issues in the code snippet :
Where is the dependencies array for the useEffect hook ?
Why adding the async keyword in both useEffect and setTimeout ?
In this line : console.log("footer == "+JSON.stringify(data??{}))
I guess you meant : console.log("footer == ",JSON.stringify(data??{}))
(same for the previous console.log)
Avoid using setTimeout if you don't need it
Import axios
Try correcting these issues then build again.

Related

Why does my useEffect() fetch data unreliably. I cannot map through the data because I am getting some undefined responses - ReactJS

I have a sidebar which sets a category Id on click and shows product information based on this Id.
In order to display each product's details, I make an api post call using axios in a useEffect() hook and setData with useState hook.
However, when I try to console.log the data, I get unreliable data back, that is, some undefined and some data.
import { useState, useEffect, useCallback, useMemo } from "react";
import axios from "axios";
import ProductCard from "../Product-cards/_medium-product-card";
const ProductDisplay = ({ subCategorySkus, categoryId, allSkus }) => {
const [data, setData] = useState();
const [isLoading, setIsLoading] = useState();
const apiRequest = { product_skus: allSkus };
const productData = useProductData(apiRequest);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.post("/products", apiRequest);
setData(response.data);
setIsLoading(false);
} catch (err) {
console.log(err.message);
}
};
fetchData();
}, [categoryId]);
console.log(data);
return isLoading ? (
" data is loading ..."
) : (
<div className="product-display">
<h3>Child component Id: {categoryId}</h3>
<ProductCard categoryId={categoryId} />
</div>
);
};
export default ProductDisplay;
You can see here what I get in the console:
.
I have tried adding an if condition, but I am not sure that addresses the issue. I have tried with different dependencies in the useEffect. But I feel there is something I am not understanding.
The api is sending the information correctly, but I get several responses in the console.log and some of them come in as undefined.
This means that I can do a data.map because it crashes the component.
Any help?
UPDATE:
#moonwave99 provided the answer (see below). For the benefit of others who may browse through this question and to clarify what the solution entails, I am including an image below, showing where I changed my code. I think that most importantly, I had not initialised my useState() to an empty array, like this: useState([]).
Any further clarification of the issues here by anyone who knows more, is welcomed. As this is only a quick fix without enough context to understand the logic.

How to Refactor an Async Function out of a React Component

I have a straightforward react component that looks so in AllWords.js :
import React, { useEffect, useState } from 'react';
import consts from '../../constants/Constants.js';
function AllWords() {
const [words, setWords] = useState([]);
async function fetchData(){
const response= await fetch(consts.FETCH_URL);
const data = await (response.json());
setWords(data);
};
// API: useEffect( () => { . . . return cleanup; },[var_n_whose_change_triggers_useEffect . . .] );
useEffect(() => {fetchData()}, [] );
return (
<>
{
words.map(w=> <div>{w.word}</div>)
}
</>
);
}
export default AllWords;
I would like to refactor the fetchData() method out of the component into another file (basically a separate .js file that holds the fetch call).
What I would like is to have created a file titled FetchAllWords.js under src/actions/ & then import it. & use that.
I have several questions :
do I need to set the state in the FetchAllWords.js and then useSelector to extract the state in AllWords.js?
in FetchAllWords.js do I need to usedispatch to dispatch a method call setting the state? I would like to just setState in FetchAllWords.js and then extract it in AllWords.js. This is what I have so far:
import consts from '../constants/Constants.js';
import { useState } from 'react';
async function FetchAllWords(){
const [words, setWords] = useState([]);
const response= await fetch(consts.FETCH_URL);
const data = await (response.json());
setWords(data);
}
export default FetchAllWords;
I am unsure how to import this and use it in AllWords.js. I am using the following statement :
import wordList from '../../actions/FetchAllWords';
Then I am trying to use wordList as a handle to the file '../../actions/FetchAllWords.js' & attempting to access the async function FetchAllWords so wordList.FetchAllWords();
Firstly , the editor (VSCode) won't let me see the function despite the import call.
Secondly I am getting an error (something like) :
TypeError: _actions_FetchAllWords_js__WEBPACK_IMPORTED_MODULE_3__.default.FetchAllWords is not a function
Any insight or help would be appreciated since rather uneasy with JS & React.
The github repo is : https://github.com/mrarthurwhite/hooks-p5-react-redux
EDIT: As per David's suggestions :
So AllWords.js React component is :
import React, { useEffect, useState } from 'react';
import wordList from '../../services/Fetch.js';
function AllWords() {
const [words, setWords] = useState([]);
function fetchData(){
wordList.fetchAllWords().then(
data => setWords(data)
);
};
// API: useEffect( () => { . . . return cleanup; },[var_n_whose_change_triggers_useEffect . . .] );
useEffect(() => {fetchData()}, [] );
return (
<>
{
words.map(w=> <div>{w.word}</div>)
}
</>
);
}
export default AllWords;
And Fetch.js is :
import consts from '../constants/Constants.js';
class Fetch {
async fetchAllWords(){
const response= await fetch(consts.FETCH_URL);
const data = await (response.json());
return data;
}
}
export default Fetch;
No, don't worry about state in the external file. Just focus on the one thing it should do, perform the AJAX operation. At its simplest it's just a function, something like:
import consts from '../../constants/Constants.js';
const fetchAllWords = async () => {
const response = await fetch(consts.FETCH_URL);
const data = await (response.json());
return data;
}
export default fetchAllWords;
You can even make it a class which contains this function, if you plan on adding other service operations as well. (Fetch specific word? Find word? etc.) The point is that this does just one thing, provide data. Let the React components handle React state.
Within the component you'd just use that to get your data. Something like:
import React, { useEffect, useState } from 'react';
import fetchAllWords from '../../services/FetchAllWords.js';
function AllWords() {
const [words, setWords] = useState([]);
useEffect(() => {
fetchAllWords().then(w => setWords(w));
}, []);
return (
<>
{
words.map(w=> <div>{w.word}</div>)
}
</>
);
}
export default AllWords;
Overall it's a matter of separating concerns. The service performs the AJAX operation and returns the meaningful data, internally concerned with things like JSON deserialization and whatnot. The React component maintains the state and renders the output, internally concerned with updating state after useEffect runs and whatnot.

console.log on useState Hook array logs several times after GET request with Axios

I have this React Component
import React, { useState, useEffect } from 'react';
import axios from "axios";
import "../../css/driversStandings.css";
function DriversStandingsComponent() {
const [data, setData] = useState([]);
var row = 1;
useEffect(() => {
axios.get("http://localhost:4000/api/standings").then(res => {
const driversChampionshipData = res.data[0].DriversChampionship
setData(driversChampionshipData);
console.log(data)
})
});
return (
//Here I return a mdbootstrap table, mapping the data array
)
}
export default DriversStandingsComponent;
I don't really understand why this happens, and if it affects the server performance.
Any idea for solving this? I don't even know if it's an error itself 😅
useEffect is called every time a component rerenders. You sholud add empty dependency array, that way useEffect calls only when component is mounted, like this:
useEffect(() => {
axios.get("http://localhost:4000/api/standings").then(res => {
const driversChampionshipData = res.data[0].DriversChampionship
setData(driversChampionshipData);
console.log(data)
})
}, []);

Why does my data appear in the console 4 times?

I'm trying to get data from a weather api using React hooks. When I console.log the data after the useEffect hook it is printed to the console 4 times, twice as an empty object. Why is that? Here is my code:
import React, {useState, useEffect} from 'react';
export default function App() {
const [data, setData] = useState({})
useEffect(() => {
fetch('https://api.weatherbit.io/v2.0/forecast/hourly?city=Chicago,IL&key=XXX&hours=24')
.then(res => res.json())
.then(response => setData(response.data))
}, []);
console.log(data)
return (
<div>
</div>
)
}
and this is what is printed in the console:
{}
{}
(24) [{},{}...]
(24) [{},{}...]
One render happens with an empty object because the component mounts. Another happens with data because you set state. And then these are both doubled due to Strict Mode

Displaying an array of objects in React native using map method

I have following component where I want to display data from an API, ShopScreen.js. I retrieve data with useEffect hook from API in service folder, and everything is ok, the json data is being loaded into data variable from useState hook, when I console.log it.
I have problem to the display data from this variable with map method. I get the error: Cannot read property 'map' of undefined. Can spot somebody where the problem is?
ShopScreen.js:
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, Button } from 'react-native';
import { fetchShops } from '../services/fetchShops';
const ShopsScreen = props => {
const [data, setShops] = useState({});
useEffect(() => {
fetchShops()
.then(response => response.json())
.then(data => setShops(data));
}, []);
return(
<View>
<Text>The Shops Screen!</Text>
{data.result.map(shop => {return (<Text>{shop.address}</Text>)})}
</View>
);
};
export default ShopsScreen;
My service for fetching data is fetchShops.js
export const fetchShops = () => {
const URL = `https://vilvumbiyl.execute-api.eu-west-1.amazonaws.com/Dev/store/MEBD/list`;
return fetch(URL)
}
useEffect without any params is equal to componentDidMount and for this reason, is called after the render.
So, the first time your jsx code is called, data.result.map is undefined and only after the re-render, do to the response of fetchShops(), it has a value.
You simply need to check the value like this:
data.result && data.result.map()
You can try:
const [data, setShops] = useState({result : {}});
or test data.result before use map on it.
ShopsScreen returns your view(JSX) before you get answer from your rest API. The result is null. You get the exception.

Categories