How to render this array in array - javascript

I want to show this advice from this API I have fetched all the data but when I try to show it, it throws the error, and also I tried to map the data but nothing works it shows errors
import React, { useState, useEffect } from 'react';
export default function App() {
const [advices, setAdvices] = useState([]);
console.log(advices); // you should have the fetch data here
async function fetchData() {
try {
const response = await fetch('https://api.adviceslip.com/advice');
const data = await response.json();
setAdvices(data.slip);
} catch (error) {
console.error(error);
}
}
useEffect(() => {
fetchData();
}, []);
return <></>;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

import React, {
useState,
useEffect
} from 'react';
export default function App() {
const [advices, setAdvices] = useState([]);
//advices will always be null here as initiated with empty array
console.log(advices); // you should have the fetch data here
async function fetchData() {
try {
const response = await fetch("http://jsonplaceholder.typicode.com/Posts");
const data = await response.json();
setAdvices(data);
} catch (error) {
console.error(error);
}
}
useEffect(() => {
fetchData();
}, []);
useEffect(() => {
console.log(advices);
}, [advices]);
return ( < > Test < />);
}

the initial value of advice should be an object and there was not another serious problem
codesand box link
import { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const [advices, setAdvices] = useState([]);
console.log(advices); // you should have the fetch data here
async function fetchData() {
try {
const response = await fetch("https://api.adviceslip.com/advice");
const data = await response.json();
setAdvices(data.slip);
} catch (error) {
console.error(error);
}
}
useEffect(() => {
fetchData();
}, []);
return (
<div className="App">
<h1>{advices.advice}</h1>
</div>
);
}

Related

react custom hook causing infinite loop

I am relatively new to react hooks and I am trying to create this custom hook to handle CRUD operations for my API.
This is the hook file:
import React, { useState, useEffect } from "react";
const useApi = (url, headers = { method: "GET" }, payload = null) => {
const [isLoading, setIsLoading] = useState(true);
const [apiData, setApiData] = useState(null);
const [serverError, setServerError] = useState(null);
const [api, setApi] = useState({});
const list = async () => {
try {
const resp = await fetch(url);
const data = await resp?.json();
setApiData(data);
setIsLoading(false);
} catch (error) {
setServerError(error);
} finally {
setIsLoading(false);
}
};
const create = async () => {
try {
const resp = await fetch(url, (headers = { method: "POST" }), payload);
const data = await resp?.json();
setApiData(data);
setIsLoading(false);
} catch (error) {
setServerError(error);
} finally {
setIsLoading(false);
}
};
setApi({
...api,
list: list,
create: create
});
return { isLoading, apiData, serverError, api };
};
export default useApi;
However, when I call api.list() in my main component inside a useEffect() hook, I get an infinite loop.
Sample component call:
import { useEffect } from "react";
import useApi from "./useApi";
export default function App() {
const {
isLoading: loading,
apiData: students,
serverError: error,
api
} = useApi("https://59f0f160ce72350012bec011.mockapi.io/students");
console.log(loading, students, error, api);
useEffect(() => {
api.list();
}, [api]);
return (
<div className="App">
<h1>list</h1>
{loading ? "loading" : students.map((x) => x.name)}
</div>
);
}
Here's the sandbox for it:
https://codesandbox.io/s/cocky-chebyshev-d9q89?file=/src/App.js:0-492
Can anyone help me understand the issue?
Thank you in advance!
This is what is causing the infinite loop:
setApi({
...api,
list: list,
create: create
});
You are not supposed to call setState() during a render.
In your case, you don't need to useState for the api object, you can just return it on every render:
return {
isLoading,
apiData,
serverError,
api: { list, create }
};
Here is a link to the fixed sandbox
Also, another warning: this code will repeatedly call api.list().
useEffect(() => {
api.list();
}, [api]);
Since api changes on every render, it will repeatedly call api.list().
This is the object that changes on every render:
return { isLoading, apiData, serverError, api };
You can ensure that you only call api.list() one time by using a ref.
import { useRef } from 'react'
// In the component
const gotRef = useRef(false)
useEffect(() => {
if (!gotRef.current) {
api.list();
gotRef.current = true
}
}, [api]);

What is wrong with my checkAuth function?

I have been trying to create a checkAuth function all day, backend is creating a token and saving it in mongodb, when someone logs in the token gets overwritten to a new token, so only one session can be logged in at a time. However, my checkAuth function always returns true.
CheckAuth.js
import React from "react"
import axios from "axios"
const checkAuth = async () => {
const userInfo = localStorage.getItem("userInfo");
const info = JSON.parse(userInfo);
const email = info.email;
const origintoken = info.token;
console.log("origin");
try {
const config = {
headers: {
"Content-type": "application/json"
}
}
const { data } = await axios.post (
"/api/users/token",
{email},
config
);
const token = data.token;
console.log("origin");
if (origintoken === token) {
console.log("origin");
return true;
}
else {
console.log("else");
return false;
}
} catch (error) {
console.log("error");
return false;
}
}
export default checkAuth
LandingPage.js
import React from "react"
import AuthCheck from "./CheckAuth.js"
import { useEffect } from "react"
import {Redirect} from "react-router-dom"
import { useState} from "react"
import checkAuth from "./CheckAuth.js"
export default function LandingPage() {
const [redirect, setRedirect] = useState(false);
useEffect(() => {
if(!checkAuth()) {
setRedirect(true);
console.log("false");
}}, [])
if (redirect) {
<Redirect to="/"/>
}
return (
<div>
<h1>whatsup</h1>
</div>
)
}
Serverside:
const checkToken = asyncHandler(async (req, res) => {
const email = req.body;
const user = await User.findOne(email)
if (user) {
res.json({
token: user.token,
});
} else {
res.status(400)
throw new Error("Niet ingelogd.")
}
});
As checkAuth is an async function, it always returns a promise which resolves to the value that you return in try block, or rejects with the value that you return in the catch block.
resolves to either true or false:
if (origintoken === token) {
console.log("origin");
return true;
}
else {
console.log("else");
return false;
}
rejects with false:
catch (error) {
console.log("error");
return false;
}
So you can't test its return value like a normal function. instead:
useEffect(async () => {
let authResult=await checkAuth();
if (!authResult) { // first correction
setRedirect(true);
}
}, [])
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function#description
The component should probably look something like this:
import React from "react"
import AuthCheck from "./CheckAuth.js"
import { useEffect } from "react"
import { Redirect } from "react-router-dom"
import { useState } from "react"
import checkAuth from "./CheckAuth.js"
export default function LandingPage() {
const [redirect, setRedirect] = useState(false);
useEffect(() => {
if (!checkAuth()) { // first correction, call the function
setRedirect(true);
}
}, [])
if (redirect) {
return <Redirect to="/"/> // second correction, missing return
}
return (
<div>
<h1>whatsup</h1>
</div>
)
}
You can also do this in the useEffect:
useEffect(() => {
setRedirect(!checkAuth())
}, [])
Update:
As suggested in an answer by Erfan Naghashlou, checkAuth is async function so that useEffect should be modified as:
useEffect(() => {
const x = async () => {
const checkAuthResult = await checkAuth()
setRedirect(!checkAuthResult)
}
x()
}, [])
Look at how to handle async await in useEffect

"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>;
};

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

I can't save data inside a Hook

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,

Categories