I have created Context API I am trying to fetch the data from my API so I can use the state globally, but is not doing it. I am not getting any errors in the console. But when I try to fetch from the Other Component, I am getting data in the console. Just in the Context, I am not getting it.
import React, {useState, useEffect}from 'react'
import ITrucks from '../interface/truck';
import axios from 'axios';
export const TrucksContext= React.createContext({})
export const TrucksProvider:React.FC = ({ children } ) => {
const [isLoading, setIsLoading] = useState(false);
const [trucks, setTrucks] =useState<ITrucks[]>([])
const [isError, setIsError] = useState(false);
const fetchData = () => {
axios
.get('https://localhost:7000/trucks')
.then((response) => {
setIsLoading(false);
setTrucks(response.data);
console.log(response.data)
})
.catch((error) => {
setIsLoading(false);
setIsError(true);
console.log(error);
});
};
useEffect(() => {
fetchData();
}, []);
return (
<TrucksContext.Provider
value={{trucks}}
>
<>
{children}
</>
</TrucksContext.Provider>
);
}
try setTrucks([...response.data])
The problem could be in the API itself. When an API has an error it often return empty data to Axios instead of an error, it depends on the return statement
Related
I've created a custom fetch component, and I'm simply trying to get an image to load on the page from an API called "the dog API". Have I missed something crucial?
App.js
import './App.css';
import './Dog.js';
import useFetch from './useFetch';
function DogApp() {
const API_KEY = "";
const { data, loading, error } = useFetch(`https://api.thedogapi.com/v1/images/search/API_KEY=${API_KEY}`);
if (loading) return <h1>Loading the dogs!</h1>
if (error)console.log(error);
return (
<div className="DogApp">
<img src={data?.url}></img>
</div>
);
}
export default DogApp;
UseFetch.js (hook for fetching the data)
import { useEffect, useState } from 'react';
import axios from "axios";
function useFetch(url) {
const [data, setData] = useState(null); //initialize as null depending on what data is
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
axios //make request, if successful it sets data, if not, seterror state
.get(url)
.then((response) => {
setData(response.data);
}).catch((err) => {
setError(err)
}).finally(() => {
setLoading(false);
});
}, [url]);
return {data, loading, error};
}
export default useFetch;
API URL I'm trying to retrieve data from : https://api.thedogapi.com/v1/images/search/
So you're API call (according to the example on thedogapi.com) requires the API key to be set in the header like so:
axios.defaults.headers.common['x-api-key'] = "DEMO-API-KEY"
That fixes the 404, but your code still won't work because the data is returned as an array of objects. So you'll need to map them like so:
{data.map((breed) => (<img src={breed?.url} />))}
I've created a demo sandbox here
I'm trying to fetch an api on a custom reactjs hook using Axios. I keep getting twice the response as undefined and after that twice as a successful fetch with the data. The undefined breaks my app.
Btw I'm fetching from the randomuser api.
import axios from "axios";
import { useState, useEffect } from "react"
export const useFetch = (url) => {
const [loading, setLoading] = useState(false);
const [data, setData] = useState([]);
const [error, setError] = useState('')
const getData = () => {
setLoading(true)
try {
axios.get(url)
.then(response => setData(response.data));
setLoading(false)
} catch (error) {
setError(error)
}
};
useEffect(() => {
getData()
}, [url])
return {loading, data, error}
}
Trying to use it here and map over it
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { useFetch } from '../custom_hooks/useFetch';
const PersonDetails = () => {
const { loading, data , error } = useFetch('https://randomuser.me/api?results=20');
const { results } = data;
const { id } = useParams();
const [person, setPerson] = useState({})
useEffect(() => {
const newPerson = results?.find(person => person.login.uuid === parseInt(id))
setPerson(newPerson)
console.log(newPerson)
}, [])
return (
<div>
{person.name.first}
</div>
)
}
export default PersonDetails
This is the thing I actually Im trying to do, but now because it is undefined, I get that cannot read properties of undefined...
When the effect runs you:
setLoading(true)
Send the Ajax request
setLoading(false)
Later, then the Ajax response arrives you:
setData(response.data)
Since you depend on loading to determine if data is set or not, it breaks.
There are two things you could do:
Move setLoading(false) inside the then callback so it doesn't get set until after you have setData(response.data)
Get rid of loading entirely and base your logic off data being undefined or having a different value.
you should define the getData function inside the useeffect or pass it in dependency array and wrap the function by usecallback to avoid unnecessary rerenders.
you should use abortcontroller in case of cancelations and to have cleanup function in useeffect. (in this case it's better to define getdata body in useeffect)
useEffect(() => {
const controller = new AbortController();
const getData = async () => {
setLoading(true)
try {
await axios.get(url, {signal: controller.signal})
.then(response => setData(response.data));
} catch (error) {
setError(error)
}
}
getData()
return()=>controller.abort()
},[url]}
you can read more about fetching data with hooks in following url and where to setloading and other needed states.
https://www.robinwieruch.de/react-hooks-fetch-data/
Just in case, this solution helped me : https://github.com/axios/axios/issues/2825#issuecomment-883635938
"The problem in my case was caused by React development server.
The strict mode in react caused the issue!
I had to remove the strict mode
This solved the problem of sending double requests!
The strict mode checks are only run in development mode.
Doc: https://reactjs.org/docs/strict-mode.html
"
I'm having two problems my code.
The first is that data is undefined, i'm not fetching data from the API.
The seccond is that the hook useEffect it's not working as it should, like componendidmount, and it's on a loop re rendering the coponent.
this is my code :
import { StatusBar } from 'expo-status-bar';
import React ,{useState,useEffect} from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
const [loading, setLoading] = useState(true);
const [users, setUsers] = useState([]);
const fetch = async () =>{
try{
let data = await fetch("https://api.sampleapis.com/coffee/hot", {method: 'GET'});
let json = await data.json();
setUsers(json);
setLoading(false);
}
catch(err){
console.log("Im catching the error");
console.log(err);
setUsers([]);
setLoading(false);
}
}
useEffect(() => {
fetch();
},[])
return (
<View style={styles.container}>
{loading?<><Text>Loading...</Text></>:<Text>Data fetched</Text>}
</View>
);
}
....
const fetch = async () =>{
....
fetch method is calling itself, try to change method name
Goal: Fetch data from api then assign it to a state for further processing.
Issue: After setting the data to my useState it is still undefined.
Questions:
How would one solve this problem?
Am I misunderstanding the useState hook?
import "./styles.css";
import axios from "axios";
import { useEffect, useState } from "react";
export default function App() {
const [userData, setUserData] = useState();
const functionz = () => {
return axios
.get("https://randomuser.me/api/")
.then(({ data }) => data.results);
};
useEffect(async () => {
const data = await functionz();
setUserData(data);
}, []);
if (userData) {
console.log(userData);
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Edit to see some magic happen!</h2>
</div>
);
}
You have to make sure your function is returning the axios call. Then await whatever comes out of it in your useEffect. Then proceed to adding it to your state. See example.
import React, { useState, useEffect } from 'react'
import axios from "axios";
const Api = () => {
const [usersData, setUsersData] = useState(null)
const fetchRandomUserData = () => axios.get('the-url')
useEffect(() => {
fetchRandomUserData()
.then(resp => {
setUsersData(resp.data.results)
})
.catch(e => {
console.log('Error: ', e)
})
}, [])
console.log(usersData)
return <div></div>
}
export default Api
I'm a very beginner in React and Next.JS. I'm doing an app and I'm using the useContext hook. So, I have this code
import { createContext } from 'react';
let data;
fetch(API_URL)
.then(response => response.json())
.then(result => {
data = result.data;
})
.catch(error);
export const UserContext = createContext(data);
The problem is that when the context is created, the value of 'data' is null. Is there a way to do this asynchronously?
Something like this should do it:
import { useState, useEffect, createContext } from 'react';
const UserContext = ({children}) => {
const [data, setData] = useState();
const Ctx = createContext();
useEffect(() => {
fetch(API_URL)
.then(response => response.json())
.then(result => {
setData(result.data);
})
.catch(error);
}, []};
return (
<Ctx.Provider value = {data} >
{children}
</Ctx>
);
}
Didn't test it, but this should give you an idea; You can use it like
<UserContext>
// your code here
</UserContext>
A better way to do it would be to extract the fetch logic in a custom hook:
const data = useUserData(); // fetch logic here
<UserContext value={data}>
// your code here
</UserContext>
but since you are a beginner in React, I would keep it simple