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>;
};
Related
import React, { useEffect, useState } from "react";
import { endpoint, apiKey } from "../api";
import Container from "../components/layouts/Container";
export default function Movie({ route }) {
const { movieId } = route.params;
const [movieDetails, setMovieDetails] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const urls = [
`${endpoint}/movie/${movieId}?api_key=${apiKey}`,
`${endpoint}/movie/${movieId}/credits?api_key=${apiKey}`,
`${endpoint}/movie/${movieId}/images?api_key=${apiKey}`,
`${endpoint}/movie/${movieId}/reviews?api_key=${apiKey}`,
`${endpoint}/movie/${movieId}/similar?api_key=${apiKey}`,
];
useEffect(() => {
const fetchData = () => {
setIsLoading(true);
Promise.all(
urls.map((url) => {
return fetch(url);
})
)
.then((response) => {
return Promise.all(response.map((res) => res.json()));
})
.then((data) => {
setMovieDetails(data);
setIsLoading(false);
})
.catch((err) => {
console.log(err);
});
};
fetchData();
}, []);
console.log(movieDetails[0]);
Hello,
I've encountered a problem tha that when i try to fetch the request above when i console.log() it it first returns undefined and then return the desired response.
The response is expected as initially the state is undefined.
During the request also, till the response is unresolved, the process is suspended and the state stays undefined.
A simple solve will be to move the console.log(movieDetails[0]) into the last .then() body or you could write your own Promise resolution functions.
I have following function.
const loadUsers= () => {
return async (dispatch) => {
dispatch(userRequest());
let response= null
try {
response= await UserService.getUser();
dispatch(userLoading());
} catch (error) {
dispatch(userError(error));
} finally {
dispatch(userSuccess(response));
}
};
};
With the following unit test I was abale to hit the "dispatch(userRequest());"
describe('user thunk', () => {
it('dispatches a userRequest', async () => {
const dispatch = jest.fn();
await loadUsers()(dispatch);
expect(dispatch).toHaveBeenCalledWith(userRequest());
});
});
However I couldn't figure out how to test lines and below response= await UserService.getUser();. Even though the function is not complex and I won't have much value for writing complex test, I need it for my pipeline to build.
Any help will be appreciated.
Thanks in advance.
UPDATE-> User Service
import axios from 'axios';
const USERS_ENDPOINT = '/user';
export const getUser= async () => {
const response = await axios.get(PRODUCTS_ENDPOINT, {});
return response.data;
};
export default getUser;
After days of research, I ended up testing the logic the following way.
import thunk from 'redux-thunk';
import configureStore from 'redux-mock-store';
import * as reactRedux from 'react-redux';
import axios from 'axios';
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
describe('load user thunk', () => {
it('dispatches load user and error on call when API is not mocked', async () => {
const store = mockStore({});
const requestDispatch= userRequest();
const errorDispatch= userError("Mock Message");
await store.dispatch(await loadUsers());
const actionsResulted = store.getActions();
const expectedActions = [
requestDispatch,
errorDispatch,
];
expect(actionsResulted.length).toEqual(expectedActions.length);
expect(actionsResulted[0].type).toEqual(expectedActions[0].type);
expect(actionsResulted[1].type).toEqual(expectedActions[1].type);
});
it('dispatches load user and success on call when API is mocked', async () => {
const store = mockStore({});
const requestDispatch= userRequest();
const successDispatch= userSuccess("Mock Data");
jest
.spyOn(axios, 'get')
.mockResolvedValue({ status: 200, data: "Mock Data"});
await store.dispatch(await loadUsers());
const actionsResulted = store.getActions();
const expectedActions = [
requestDispatch,
successDispatch,
];
expect(actionsResulted.length).toEqual(expectedActions.length);
expect(actionsResulted[0].type).toEqual(expectedActions[0].type);
expect(actionsResulted[1].type).toEqual(expectedActions[1].type);
});
I am calling this api inside a context provider:
const url = 'http://127.0.0.1:8000/api/posts/'
const PostListContextProvider = (props) => {
const [posts, setPosts] = useState([])
useEffect(async () => {
const {data} = await axios.get(url);
setPosts(data)
}, [posts]);
return (
<PostListContext.Provider value={ posts }>
{ props.children }
</PostListContext.Provider>
);
}
Upon consuming the context using useContext, this error occurs:
react-dom.development.js:19710 Uncaught TypeError: destroy is not a function
What am I doing wrong?
ps.even though I am getting the error, I am still successfully fetching the data
useEffect should not be async
Do it like this:
useEffect(() => {
(async () => {
const {data} = await axios.get(url);
setPosts(data)
})()
}, [posts]);
useEffect is supposed to return a function if it returns something, since you are defining the callback function to useEffect as a promise, what it essentially returns is a promise which is not what it expects.
In order to use a async function within useEffect you would write it like
useEffect(() => {
async function myFn() {
const {data} = await axios.get(url);
setPosts(data)
}
myFn();
}, [posts]);
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();
}, [])
I'm learning Hooks with React and I'm trying to do a simple fetch to an API then I'm trying to save that data inside a Hook but It has not been possible for me.
import React, { useState, useEffect } from "react";
function useDogs() {
const [dogs, setDogs] = useState({
data: {}
});
useEffect(() => {
const fectData = async () => {
const data = await fetch("https://dog.ceo/api/breeds/image/random");
setDogs({ data: data.url });
console.log(data.url);
};
fectData();
}, []);
}
function Dogs() {
const dogs = useDogs();
console.log("dogs", dogs);
return <ul>{dogs} dogy</ul>;
}
export default Dogs;
In component Dogs() I'm having dogs as undefined
You aren't returning dogs from your useDogs hook.
(Also, to get at the response data, you need to await on .json() from the fetch response.)
import React, { useState, useEffect } from "react";
function useDogs() {
const [dogs, setDogs] = useState({
data: {},
});
useEffect(() => {
const getData = async () => {
const resp = await fetch("https://dog.ceo/api/breeds/image/random");
const data = await resp.json(); // <-- this
setDogs({ data });
console.log(resp, data);
};
getData();
}, []);
return dogs; // <-- this
}
function Dogs() {
const dogs = useDogs();
console.log("dogs", dogs);
return <ul>{dogs} dogy</ul>;
}
export default Dogs;
Custom Hooks are just javascript functions if you want to assign them to a variable you need to return something in your custom hook,
In some situations you need to set Something into your custom hook which you can do that by returning both value and setValue functions, for example in your case like below:
import React, { useState, useEffect } from "react";
function useDogs() {
const [dogs, setDogs] = useState({
data: {},
});
useEffect(() => {
const getData = async () => {
const resp = await fetch("https://dog.ceo/api/breeds/image/random");
const data = await resp.json(); // <-- this
setDogs({ data });
console.log(resp, data);
};
getData();
}, []);
return [dogs, setDogs]; // <-- this
}
and when you want to use it you just destructure it like this:
function Dogs() {
const [dogs, setDogs] = useDogs();
console.log("dogs", dogs);
return <ul>{dogs} dogy</ul>;
}
export default Dogs;
now you can read the data and also in future cases if you'ld like you can set the data too,