I’m trying to make a small app that reads an endpoint to get a list of items. The app will then loop through and pull the details for the items. I did get a version to work but it breaks the rules of hooks. What is the standard / correct way?
This code should trigger the useEffect on load to set the Globals. Then trigger the useEffect to setLocalData and then trigger the useEffect to add the localdata to the localDataList
When I run this code I get the list of the 2 global lines. That works great. The details part is where it gets wonky. First, I can’t figure out how to get rid of the leading null in the local. Secondly, if I refresh over and over, I get only 1 item sometimes.
import React from 'react';
import { useState, useEffect } from 'react';
import { Buffer } from 'buffer';
import algosdk from 'algosdk';
export declare module DataStore {
export interface Events {
"global-state": KeyValue[];
}
export interface EventDetails {
"key-value": KeyValue[];
}
export interface Value {
bytes: string;
type: number;
uint: number;
}
export interface KeyValue {
key: string;
value: Value;
}
}
function App() {
const [globals, setGlobals] = useState<DataStore.Events[]>([]);
const [localDataList, setLocalDataList ] = useState<any>([])
const [localData, setLocal] = useState<DataStore.EventDetails[]>();
useEffect(() => {
fetch("https://node.algoexplorerapi.io/v2/applications/1022971265")
.then((response) => response.json())
.then((data) => setGlobals(data.params["global-state"].filter((item: any) => item.key !== "VGl0bGU=" )));
}, []);
useEffect(() => {
globals.forEach(function (item: any) {
//console.log(globals);
const pretty_address = algosdk.encodeAddress(new Buffer(item.value.bytes, 'base64'));
//console.log(pretty_address)
fetch("https://node.algoexplorerapi.io/v2/accounts/" + pretty_address + "/applications/1022971265")
.then((response) => response.json())
.then((data) => setLocal(data["app-local-state"]["key-value"] )); //
})
}, [globals]);
useEffect(() => {
console.log(localData)
setLocalDataList([...localDataList, localData ])
}, [localData]);
return (
<div>
Globals:
<ul>
{globals.map((item: any) => (
<li key={item.key}>{
JSON.stringify(item)
}</li>
))}
</ul>
<br/>
Local list:
<ul>
{localDataList?.map((item) => ( <li> {JSON.stringify(item)} </li> )) }
</ul>
</div>
);
}
export default App;
Thanks for the help.
2
Answers
to remove null, replace
with
then there seems being a problem with global.foreach, you will repeteadly overwrite the localldata content since your are not adding items, but replacing them with this line :
prefer :
finally, useState<DataStore.EventDetails[]>(); is not initialized
In your situation I would create a free function to do all the work, and return it once completed.
Then you component can be something like
If you want to fetch from inside components like this I would however sugges you use something like react-query or SWR. It will deal with batching, concurrent calls, caching etc for you and make life easier.
Also, just to cover all the bases. Error checking here is omitted, but should be included in any code you actually planning to use.