Connecting 2 different arrays from the same external link - React hooks fetch - reactjs

I am able to fetch data what url, but the thing is the url is divided into couple of arrays and I need to fetch data and connect them.
Example:
{
"array1": [
{ "data1": {"name": "Name", "phone": "Phone"}}
]
"array2" : [
{ "data2": { "color": "Color", "car": "Car" } }
]
}
Data hooks :
const userInfo = "URL";
const [userData, setUserData] = useState([]);
useEffect(() => {
getUserInfo();
}, []);
const getUserInfo = async () => {
const response = await fetch(UserInfo);
const jsonData = await response.json();
setUserData(jsonData);
};
Fetch data:
{ userData.data && userData.array1.map((array1, index) =>
<li key={"index" + index}
<h5>{array1.data1.name} </h5>
</li>
)}
I need to connect name from array1 with color from array2, but I can not find the way to do it.
Expected Output : list of data

If you can get those two arrays then you can use this to combine them:
const getUserInfo = async () => {
const response = await fetch(UserInfo);
const jsonData = await response.json();
// this assumes `jsonData` in an object with keys `array1` and `array2`
// if this is not the case, change `jsonData` below to the location of
// those two arrays
const { array1, array2 } = jsonData;
const combinedArray = array1.map(({ data1 }, i) => ({
...data1,
...array2[i].data2 // assumes there is always a corresponding index in array 2
}));
// combinedArray will look like [ { name: 'Name', phone: 'Phone', color: 'Color', car: 'Car' } ] 
setUserData(combinedArray);
};
] 

Related

Can't use the data from API when app just starts

My data is undefined when the app is started but after the refresh, the data comes perfectly.
For startup
It gives me [Unhandled promise rejection: TypeError: Object.entries requires that input parameter not be null or undefined]
But after the refresh, the data comes perfectly and everything working.
This is part of my data
Object {
"attributes": Object {
"htmlName": null,
"id": 0,
"items": Array [
Object {
"htmlName": "r_1",
"name": "m2 (Brüt)",
"numeric": true,
"options": Object {},
"order": 0,
"required": true,
},
Object {
"htmlName": "r_2",
"name": "m2 (Net)",
"numeric": true,
"options": Object {},
"order": 0,
"required": true,
},
Object {
"htmlName": "r_164",
"name": "Arsa Alanı (m2)",
"numeric": true,
"options": Object {},
"order": 0,
"required": true,
},
Object {
"htmlName": "a_137",
"name": "Oda Sayısı",
"numeric": false,
"options": Object {
"12": "1+0",
"13": "1+1",
"14": "1.5+1",
"15": "2+0",
"16": "2+1",
"17": "2.5+1",
"18": "2+2",
"19": "3+1",
"20": "3.5+1",
"21": "3+2",
"22": "4+1",
"226": "0+1",
"23": "4.5+1",
"24": "4+2",
"25": "4+3",
"26": "4+4",
"27": "5+1",
"28": "5+2",
"29": "5+3",
"30": "5+4",
"31": "6+1",
"32": "6+2",
"33": "6+3",
"34": "7+1",
"35": "7+2",
"36": "7+3",
"37": "8+1",
"38": "8+2",
"39": "8+3",
"40": "8+4",
"41": "9+1",
"42": "9+2",
"43": "9+3",
"44": "9+4",
"45": "9+5",
"46": "9+6",
"47": "10+1",
"48": "10+2",
"49": "10 Üzeri",
},
"order": 0,
"required": true,
},
api.js
export const getData = function () {
return axios
.get(
"blabla",
{
headers: {
Authorization: `blabla`,
},
}
)
.then((json) => {
if (json && json.status === 200) {
//console.log(json);
return json.data;
}
})
.catch((e) => {
console.log(e);
});
};
App.js
const [data, setData] = useState({});
const [roomValue, setRoomValue] = useState(null);
const [roomCount, setRoomCount] = useState([]);
const [isFocus, setIsFocus] = useState(false);
useEffect(() => {
getDataFunc();
//setDropdown(data.attributes.items[3].options);
}, []);
const getDataFunc = async () => {
const res = await getData();
//console.log(res);
setData(res);
console.log(data);
};
function setDropdown(query) {
const response = query;
try {
const entries = Object.entries(response);
const tempArray = [];
for (let i = 0; i < entries.length; i++) {
var key;
var value;
(key = entries[i][0]), (value = entries[i][1]);
tempArray.push({ key: value, value: key });
}
setRoomCount(tempArray);
//console.log(roomCount);
} catch (error) {
//console.log(error);
}
}
How can I fix that ?
Add a seperate useEffect to check wheather the data has been set and then only set the dropdown values
useEffect(() => {
getDataFunc();
}, []);
useEffect(() => {
if(data && data.attributes?.items[3]){
setDropdown(data.attributes.items[3].options);
}
}, [data]);
const getDataFunc = async () => {
const res = await getData();
//console.log(res);
setData(res);
console.log(data);
};
It seems like the error is caused by the attributes property being empty when you try to access it. But when you assign them one by one then it loads because the data is loaded per nested property before assigning it to the variable. Means it hasn't fully loaded yet
const response = data.attributes.items[3].options;
It outputs an error because attributes is undefined. So it's not an object, therefore, attributes.items is considered invalid
// sample
const data = {
/* attributes: {
items: {
1: {
options: 'option1'
},
2: {
options: 'option2'
},
3: {
options: 'option3'
}
}
} */
}
const specificData = data.attributes.items[3].options
console.log(specificData) //
So one solution would be using the optional chaining operator to avoid the error, it's just basically a question mark (?) after the object you are trying to access.
The response would be then 'undefined'. That way even if the attributes is empty or not, data will be assigned to the response constant then you can just add some more checking outside of that.
// sample
const data = {
/* attributes: {
items: {
1: {
options: 'option1'
},
2: {
options: 'option2'
},
3: {
options: 'option3'
}
}
} */
}
const specificData = data.attributes?.items[3].options
console.log(specificData) // outputs undefined instead of an error
Let me know if this works btw. maybe you could provide the actual api or maybe a sample api endpoint so we could test it directly. Or maybe the full code?
I've encoutered this before though I'm not 100% sure this is all I've done. But for the error I'm sure the optional chaining operator will prevent it
Try calling getData inside an async function and wait for the process to complete like this in your App.js
const [data, setData] = useState([]);
const [roomCount, setRoomCount] = useState([]);
useEffect(() => {
getDataFunc()
}, []);
const getDataFunc = async() => {
await getData(setData);
const response = data;
console.log(response);
const entries = Object.entries(response);
const tempArray = [];
for (let i = 0; i < entries.length; i++) {
var key;
var value;
(key = entries[i][0]), (value = entries[i][1]);
tempArray.push({ key: value, value: key });
}
setRoomCount(tempArray);
console.log(roomCount);
}
note: The best practice is not to directly pass the setData function to getData api call instead return the response from api and assign the response in main code like below
const response = await getData();
setData(response)
From what I see, your data.attributes has undefined value.
Please double-check everything, it is technically impossible to get data directly if data.attributes is undefined

How to inject string into api response in react native?

I have an array of objects response that comes from API. I don't have access to the API to be able to change it.
data = [
{"label": "Group 1", "value": "1"},
{"label": "Group 2", "value": "2"},
{"label": "Group 3", "value": "3"}
]
I need to display the data, so the label says Post to ${label}.
Can I inject the 'Post to ' string somehow? Do I make a new array from my response?
Here's how I'm fetching the data:
const [pickerData, setPickerData] = React.useState<{ label: string; value: string }[]>([]);
const fetchPickerData = React.useCallback(async () => {
const response = await getPostLocations();
if (!response) return;
if (response) {
setPickerData(response);
}
}, []);
React.useEffect(() => {
fetchPickerData().catch(console.error);
}, [fetchPickerData]);```
and my data is then loaded into a picker:
<Picker
items={pickerData}
value={pickerItem}
onValueChange={(pickerItem) => setPickerItem(pickerItem)}
/>
Things I already tried is trying to inject string into value like value={()=>{`Post to ${pickerItem}`}}, or the same in the setPickerItem in onValueChange but that didn't work
You can use Array#map() to create a new array from the response in the format you prefer:
const fetchPickerData = React.useCallback(async () => {
const response = await getPostLocations();
if (!response) return;
if (response) {
const formattedResponse = response.map(
({ label, value }) => ({ 'label': `Post to ${label}`, value })
)
setPickerData(formattedResponse);
}
}, []);
Try it like this
const [pickerData, setPickerData] = React.useState<{ label: string; value: string }[]>([]);
const [apiData, setApiData] = React.useState<{ label: string; value: string }[]>([]);
const fetchPickerData = React.useCallback(async () => {
const response = await getPostLocations();
if (!response) return;
if (response) {
setApiData(response);
}
}, []);
React.useEffect(() => {
fetchPickerData().catch(console.error);
}, [fetchPickerData]);
React.useEffect(() => {
if (apiData.length > 0) {
let Temp = [];
apiData.forEach((item) => {
let newItem = {
...item,
label: `Post to ${item.label}`
};
Temp.push(newItem);
});
setPickerData(Temp);
}
}, [apiData]);

Return in tabular format in reactjs

I'm new to web dev and currently trying to develop a dashboard.
My api data returns like this:
{
'ada': {'available': '45', 'profit': '-0.5'},
'eth':{'available': '2', 'profit': '5'}
}
and the code that gets the data is
useEffect(() => {
const fetchAPI = async() => {
const resp = await httpClient.get("//localhost:5000/dashboard")
data = resp.data
console.log(data)
if(data){
keys_list = Object.keys(data).map((crypto) => crypto)
data_list = Object.values(data).map((crypto) => crypto.current)
setChartData({
labels: keys_list,
datasets: [
{
label: 'Price in KRW',
data: data_list,
backgroundColor: [
"#ffbb11",
"#ecf0f1",
"#50AF95",
"Blue",
"Purple",
"Red",
"Green"
]
}
]
});
}
};
fetchAPI()
}, []);
const [chartData, setChartData] = useState({datasets: []})
I would like to make a sort of table that just returns the different values of each keys.
token available profit
ada 45 -0.5
eth 2 5
Any insights would be highly appreciated

Getting Error: Cannot read properties of undefined (reading 'map') chartjs

Im kind of new to web dev and stuck at a problem when trying to visualize data using a doughnut chart from chartjs.
useEffect(() => {
const fetchAPI = async() => {
const resp = await httpClient.get("//localhost:5000/dashboard")
const data = resp.data
// console.log("From fetchapi", Object.values(data).map((crypto) => crypto.current))
const keys_list = Object.keys(data).map((crypto) => crypto)
const data_list = Object.values(data).map((crypto) => crypto.current)
//console.log(data_list)
setChartData({
labels: keys_list,
datasets: [
{
label: 'Price in KRW',
data: data_list,
backgroundColor: [
"#ffbb11",
"#ecf0f1",
"#50AF95"
]
}
]
});
};
fetchAPI()
}, []);
const [chartData, setChartData] = useState({})
return(
<div><Doughnut data = {chartData}</div>
)
data here looks like this
{'eth': {'available': '0.5', 'current': '890'}, 'ada': {'available': '43.9', 'current': '24'}}
so I'm trying to put data as data.current, here would be ['890', '24'] and the labels as ['eth', 'ada']
However I'm getting an Uncaught TypeError: Cannot read properties of undefined (reading 'map') error.
Any help would be highly appreciated!
Your data is asynchronous. On page load, data is undefined until your data arrives. Add interrogation point like this, which means to make a map if the data exists
useEffect(() => {
const fetchAPI = async() => {
const resp = await httpClient.get("//localhost:5000/dashboard")
const data = resp.data
// console.log("From fetchapi", Object.values(data).map((crypto) => crypto.current))
if(data){
const keys_list = Object.keys(data).map((crypto) => crypto)
const data_list = Object.values(data).map((crypto) => crypto.current)
//console.log(data_list)
setChartData({
labels: keys_list,
datasets: [
{
label: 'Price in KRW',
data: data_list,
backgroundColor: [
"#ffbb11",
"#ecf0f1",
"#50AF95"
]
}
]
});
}
};
fetchAPI()
}, []);

In react-table with React Hooks, how to make a get request inside Cell?

I have been working with React-table for a couple of days now, my first time using it, and I have ran into some issues I can't quite seem to resolve. I am trying to build a table where I can show data from two API get requests at the same time, and since I don't know if there is a way to connect the two requests data into one object, and I wouldn't know how to do it, I was trying to access some of the data with get requests inside the react-table Column Cell itself.
My case being: I have two objects, Contacts and Institutions, contacts have in their data the institution ID as parameter, and I need to show in the table both the contact information and some information of the institution that is linked to it, getting it from the institution ID that is present in the contact data.
Here is one example of contact:
{
"contact_id": "34378a25-fe8c-4c64-bd35-59eab3f30863",
"institution_id": "ae1d0fe8-cce1-40ef-87d7-729dfbe9716d",
"name": "Contato 2",
"role": "Cargo 1",
"phone_numbers": [],
"emails": [],
"createdAt": "2021-03-09T20:40:26.6863764Z",
"updatedAt": "2021-03-09T20:40:26.686376448Z",
"deleted": false
}
And here is the institution data:
{
"institution_id": "ae1d0fe8-cce1-40ef-87d7-729dfbe9716d",
"name": "Matheus Salles Blanco",
"socialReason": "teste",
"cnpj": "99999999999999",
"abbreviation": "Matheus",
"website": "teste.com",
}
This is the code that is being implemented, reduced to only the parts that matter and that is working, but only showing the info that is being fetched from the contact object:
const Contacts = ({ match }) => {
const [data, setData] = useState([]);
const [institution, setInstitution] = useState();
const dataRecoil = useRecoilValue(contactData);
const handleContact = useCallback(async () => {
const response = dataRecoil.data;
if (response) {
setData(response.filter((contact) => !contact.deleted));
}
}, [setData, dataRecoil]);
useEffect(() => {
handleContact();
}, [handleContact]);
const columns = useMemo(
() => [
{
Header: 'Nome',
accessor: 'name',
},
{
Header: 'Sigla',
accessor: 'abbreviation',
},
{
Header: 'Nome Fantasia',
accessor: 'institution_id',
},
],
[editToggle, handleDelete],
);
return (
<>
<Table columns={columns} data={data} />
</>
);
};
And a print of it:
And here is what I have been trying to do:
const Contacts = ({ match }) => {
const [data, setData] = useState([]);
const [institution, setInstitution] = useState();
const dataRecoil = useRecoilValue(contactData);
const handleContact = useCallback(async () => {
const response = dataRecoil.data;
if (response) {
setData(response.filter((contact) => !contact.deleted));
}
}, [setData, dataRecoil]);
useEffect(() => {
handleContact();
}, [handleContact]);
const columns = useMemo(
() => [
{
Header: 'Nome',
accessor: 'name',
},
{
Header: 'Sigla',
accessor: 'abbreviation',
},
{
Header: 'Nome Fantasia',
accessor: 'institution_id',
Cell: async ({ cell }) => {
const response = await getInstitutionById(cell.row.values.institution_id);
const result = [response.data];
const inst = result.map((inst) => {return inst.name});
const institution_name = inst[0];
console.log(institution_name);
return institution_name;
},
},
],
[editToggle, handleDelete],
);
return (
<>
<Table columns={columns} data={data} />
</>
);
};
Which works at the level of fetching the right data, but does not render the page and shows errors:
The error
The right data being shown in the console.log
The expected output would be to show those names on the console.log on place of that long ID of the first picture.
So, is it possible to do what I am trying to do? And if so, what might am I be doing wrong?
I believe the issue is that you are providing an async function for your cell, which will return a Promise, not the institution name as you are expecting.
A potential solution is to instead create a custom Cell component that uses state to store the institution name. I have provided an example below, which was guided by this example, however I have not tested the code at all, so use it as more of a guide.
const MyCell = ({ cell }) => {
const [institutionName, setInstitutionName] = useState('fetching...')
useEffect(() => {
const getInstitutionName = async (id) => {
const response = await getInstitutionById(id);
const result = [response.data];
const inst = result.map((inst) => {return inst.name});
const institution_name = inst[0];
console.log(institution_name);
setInstitutionName(institution_name)
}
getInstitutionName(cell.row.values.institution_id)
}
return institutionName
}
const Contacts = ({ match }) => {
const [data, setData] = useState([]);
const [institution, setInstitution] = useState();
const dataRecoil = useRecoilValue(contactData);
const handleContact = useCallback(async () => {
const response = dataRecoil.data;
if (response) {
setData(response.filter((contact) => !contact.deleted));
}
}, [setData, dataRecoil]);
useEffect(() => {
handleContact();
}, [handleContact]);
const columns = useMemo(
() => [
{
Header: 'Nome',
accessor: 'name',
},
{
Header: 'Sigla',
accessor: 'abbreviation',
},
{
Header: 'Nome Fantasia',
accessor: 'institution_id',
Cell: MyCell
},
],
[editToggle, handleDelete],
);
return (
<>
<Table columns={columns} data={data} />
</>
);
};

Resources