Here is the new script with the find function which allows me to identify a single element of the array for sure but there is still a small problem. As you can see it's my const crypto which contains the data I want to display on the front end. However when I want to call crypto at the return level the const is not recognized.
Hello again,
I updated the script now it works I can display on the front end the data I want however I have the impression that the request to the api is executed several times when I would like there to be only one request
I put below a screen of the console.log of my script.
As you can see the data requested is displayed first as undefined then it is displayed several times, then I put blocked due to the too large number of requests made in little time
Thanks for your help
How do I make my requests :
import { useState, useEffect } from "react";
function App() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null)
useEffect(() => {
fetch("http://localhost:4500/coingeckotest")
.then(response => {
if (response.ok) {
return response.json()
}
throw response;
})
.then(data => {
setData(data)
})
.catch(error => {
console.error("Error fetching data: ", error)
setError(error)
})
.finally(() => {
setLoading(false)
})
}, [])
const uniswap = data&&data[0].tickers?.find(donne =>
donne.trade_url === 'https://app.uniswap.org/#/swap?
inputCurrency=0x2260fac5e5542a773aa44fbcfedf7c193bc2c599&
outputCurrency=ETH')
const uniprice = uniswap?.converted_last?.usd
const sushiswap = data&&data[1].tickers?.find(donne =>
donne.trade_url === 'https://app.sushi.com/swap?
inputCurrency=0x2260fac5e5542a773aa44fbcfedf7c193bc2c59
9&outputCurrency=ETH')
const sushiprice = sushiswap?.converted_last?.usd
const curvefinance = data&&data[2].tickers?.find(donne =>
donne.base === 'DAI')
const curveprice = curvefinance?.converted_last?.usd
const quickswap = data&&data[3].tickers?.find(donne =>
donne.trade_url === 'https://quickswap.exchange/#/swap?
inputCurrency=0x0d500b1d8e8ef31e21c99d1db9a6444d3adf127
0&outputCurrency=0xbbba073c31bf03b8acf7c28ef0738decf369
5683')
const quickprice = quickswap?.converted_last?.usd
console.log(uniprice)
console.log(sushiprice)
console.log(curveprice)
console.log(quickprice)
if (loading) return "Loading..."
if(error) return "Error !"
return (
<>
</>
)
}
export default App;
Thank you in advance for your answers
You can use the Array.find method to find out the first entry that matches a particular coin_id. The code for that would be:
const desiredCoinID = "something"; (determined by some user input)
const desiredCoinObject = data.find(coin => coin.coin_id === desiredCoinID);
const priceInUSD = desiredCoinObject?.tickers?.converted_last?.usd;
——-Updated Answer——-
Hi, this is my answer to your updated question. const crypto that you use is available only within the scope of the callback of the useEffect function, which is why you cannot see the results on your screen. There are two ways you can go about it:
First, you can declare crypto as a let outside the useEffect and then update it inside your useEffect. That way your crypto will have global scope. But there is a better way to do this, which is to use the useState hook.
You can declare a crypto, setCrypto using useState and then use the setter to update the value if crypto inside useEffect after the data fetching is over. Let me know if you need help writing code.
Related
const response = product.map((item) => {
return item.images;
});
console.log("response is ", response);
const [productItem, setProductItem] = useState(response);
console.log("usestate is ", productItem);
please help me as soon as possible I am stuck here for like 3 days and don't know what to do
I have tried alot to solve this issue and it is working in console before usestate initialization but once I add usestate hook it will not show up
Initially declare the state as null / empty array
const [productItem, setProductItem] = useState(null)
Then use useEffect to set the response to state.
useEffect(() => {
const product = [........]
const response = product.map((item) => {
return item.images;
});
setProductItem(response)
},[])
I'm trying to make a workable App where you get from an API some data and that data is randomly changes every 3 seconds and with a button the user can print the data and by pressing again it stops, i have managed to complete this(as seen bellow) part(btw new to react js):
useEffect(() =>{
const interval = setInterval(() => {
getJoke()
},3000);
return () => clearInterval(interval);
},[])
//fetch the jokes function
const getJoke = (() => {
fetch('https://api.chucknorris.io/jokes/random')
.then((res) => res.json())
.then((res) => {
setKey(res.id);
setJoke(res.value);
})
.catch((err) => console.log(err));
})
i have also made a button where the user can save the data(which randomly appears every 3 sec) on the localStorage of the browser as seen bellow..
const addJokeFav = (() => {
jokes.push(joke);
const jokesJsonified = JSON.stringify(jokes);
localStorage.setItem(key, jokesJsonified);
})
bellow the render code
<button id="button" onClick={()=>{addJokeFav()}}>Save!</button>
but i would like to have only one button where he save one data coming randomly and every 3 seconds, and if he repress the button the data will be deleted from the localStorage. i have this function here which i dont seem to make it work.
const remJokeFav = (() => {
const jokesJsonified = JSON.stringify(jokes);
localStorage.removeItem(key, jokesJsonified);
})
it seems that is trying to remove and item that is not there cause of the key, which i take it with setKey(res.id) on the response, on the code above in the first snippet.
my App variables are bellow.
const [joke, setJoke] = useState();
const [key, setKey] = useState([]);
const [isActive, setActive] = useState("false");
const jokes = [];
Thanks for any help regarding the situation!
The problem looks to be with localStorage.removeItem(key, jokesJsonified);
removeItem just needs the key and not the value.
Also there is unnecessary rerender on setting jokes array. Make jokes array as ref instead of state.
Here is an working example in codesandbox
I have an Effect hook in a React component that sets up and initialises a class that I use to communicate with a backend server:
const SignalProvider = ({url, children}) => {
let [sigErr, setSigErr] = useState("")
let [token, setToken] = useContext(TokenContext)
let [signaller, setSignaller] = useState()
useEffect(() => {
if (!signaller) {
const s = new Signaller(url, (err) => setSigErr(err))
setSignaller(s)
}
if (token && signaller) {
signaller.setToken(token)
signaller.setSetTokenCallback(setToken) // Adding this line causes an infinite loop
signaller.connect()
}
}, [url, token, signaller, setToken, authError])
...
}
However, adding the line signaller.setSetTokenCallback(setToken) causes an infinite loop of re-rendering. Without this line it works as expected.
All setSetTokenCallback does is:
setTokenCallback(f) {
this.setTokenCallback = f
}
Which I don't think should matter.
Whats the best way to prevent the loop?
Have you tried using 'useCallback()' hook?
const initializeClass = useCallback(() => {
if (!signaller) {
const s = new Signaller(url, (err) => setSigErr(err))
setSignaller(s)
}
if (token && signaller) {
signaller.setToken(token)
signaller.setSetTokenCallback(setToken)
signaller.connect()
}, [url, token, signaller, setToken, authError])
useEffect(() => {
initializeClass()
}, [bla bla all dependencies needed])
I think your culprit is in these lines
signaller.setToken(token) // first possible culprit
signaller.setSetTokenCallback(setToken)
Since you are setting the token inside the useEffect and your useEffect depends on the token value for a re-evaluation again. If the token value is different than the previous one then it will make the useEffect to re-render.
[url, token, signaller, setToken, authError] // second possible culprit
Also, you should remove object or array type variables from the condition array [url, token, signaller, setToken, authError] or stringify them or find some way to compare, as objects and arrays can't be compared directly. They will always return false if directly compared. Thus, your useEffect will re-run.
Background
I'm building an app which displays a number of stores in the home screen. They are shown in a carousel which is filled up with information from a Firestore Collection and Firebase Storage. The user can navigate into each store by pressing on them. The Home Screen display works just fine every single time, but when navigating to one store components come back as undefined. This is the way I'm fetching the data:
export default function StoreDetailMain ({route}) {
const { storeId } = route.params
const [store, setStore] = useState()
useEffect(() => {
const fetchQuery = async () => {
const storeData = await firebase.firestore()
.collection('stores/')
.doc(storeId)
.get()
.then(documentSnapshot => {
console.log('Store exists: ', documentSnapshot.exists);
if (documentSnapshot.exists) {
console.log('Store data: ', documentSnapshot.data());
setStore(documentSnapshot.data())
console.log(documentSnapshot.data())
}
});
}
fetchQuery()
}, [storeId])
Then I'm rendering the information within tags as in <Text>{store.value}</Text>.
Problem
Navigating once to the store will always return a Component Exception: undefined is not an object (evaluating 'store.value'). However if I cut the "{store.value}" tags it works just fine. Then I can manually type them in again and they render perfectly. Once I go back to the Home Screen and try to go into another store I have to do it all again. Delete the calls for information within the return(), save the code, reload the app and type them in again.
What I have tried
Sometimes, not always, Expo will give me a warning about not being able to perform a React state update on an unmounted component. I thought this might be the problem so I gave it a go by altering my useEffect method:
export default function StoreDetailMain ({route}) {
const { storeId } = route.params
const [store, setStore] = useState()
useEffect(() => {
let mounted = true;
if(mounted){
const fetchQuery = async () => {
const storeData = await firebase.firestore()
.collection('stores/')
.doc(storeId)
.get()
.then(documentSnapshot => {
console.log('Store exists: ', documentSnapshot.exists);
if (documentSnapshot.exists) {
console.log('Store data: ', documentSnapshot.data());
setBar(documentSnapshot.data())
console.log(documentSnapshot.data())
}
});
}
fetchQuery()
}
return () => mounted = false;
}, [storeId])
This would not solve the issue nor provide any variation.
Question
Is this due to the unmounting/mounting of components? If so, wouldn't the useEffect method take care of it? If anyone could provide an explanation/solution it would be very much appreciated.
Thanks in advance.
Edit 1:
When the application fails to render the information, it doesn't print into the console the document snapshot. When it can render the data, it does log it. Thus the change in title.
try giving it a initial value
const [ store, setStore ] = useState({value: ''})
or render it conditionally
{ store?.value && <Text>{store.value}</Text> }
secondly, route.params is defined? When you switching screens, did u make sure u pass the params? Switching from stack navigator to tab navigator for example, may drop the params.
I have a react component with this state
const [name, setName] = useState('')
const [comment, setComment] = useState('')
const [notes, setNotes] = useState([])
this function handles the input elements to fill the order
const handleComments = () => {
setNotes([...notes, {
name,
comment
}])
setName('')
setComment('')
}
and this function sends the info to the server
const update = async () => {
const newNotes = notes.map(note => ({
name,
comment
}))
return updateNotesPromise(newNotes)
}
here I have a button that has to execute both functions
<Button onClick={} />
How can I create a function that is passed through the onClick method and executes handleComments in order to load the info on the DOM and then, once that info there, executes the update function and saves the order info into the DB ?
It looks like you're using functional components, so you can create a useEffect that makes an API put request whenever notes gets updated:
useEffect(()=> {
updateNotesPromise(notes);
},[notes])
I'm assuming updateNotesPromise is a function that makes your request call? It's also unclear why newNotes is being mapped from notes, or why update is async when it doesn't await anything. Your onClick would simply trigger handleNotes (I'm assuming that is your submit button).
Here's a way to handle the component updating and server communicating with error handling:
const onButtonClicked = useCallback(async (name, comment) => {
// cache the olds notes
const oldNotes = [...notes];
// the updated notes
const newNotes = [...notes, {
name,
comment
}];
// update the component and assume the DB save is successful
setNotes(newNotes);
try {
// update the data to DB
await updateNotesPromise(newNotes);
} catch(ex) {
// when something went wrong, roll back the notes to the previous state
setNotes(oldNotes);
}
}, [notes]);