Setting Data in Main Function Defined in getInitialProps - reactjs

In my NextJS app, I get initial data via getInitialProps;
TvApp.getInitialProps = async (ctx) => {
const res = await axios.get(`http://192.168.1.2:8090/api/tv_app/:${lineId}`)
const data = await res
return { data: data.data }
}
I use that data like this;
export default function TvApp(data) {
return (
<div className={styles.container}>
<h2 className={styles.bigAmount}>
{data.data.thirdScreen[0] && data.data.thirdScreen[0].AMOUNT}
</h2>
</div>
);
}
I also want to update my view in every 10 seconds.
My problem is I cannot set the data previously defined in getInitialProps.
export default function TvApp(data) {
useEffect((data) => {
const timer = setInterval(() => {
axios.get(`http://192.168.1.2:8090/api/tv_app/:${lineId}`)
.then(response => ) //This line should set the data with response
.catch(error => {
console.error(error.response.data);
});
return () => clearInterval(timer);
}, 10000);
}, []);
return (
<div className={styles.container}>
<h2 className={styles.bigAmount}>
{data.data.thirdScreen[0] && data.data.thirdScreen[0].AMOUNT}
</h2>
</div>
);
}
How can I set the data in useEffect?
This is probably a very basic question but I cannot find a way.

You can use sate variable to hold the data if it has to be updated in component
export default function TvApp(props) {
const [data,setData] = useState(props.data);
useEffect(() => {
const timer = setInterval(() => {
axios.get(`http://192.168.1.2:8090/api/tv_app/:${lineId}`)
.then(response =>
setData(response.data);
) //This line should set the data with response
.catch(error => {
console.error(error.response.data); });
return () => clearInterval(timer);
}, 10000);
}, []);
return (
<div className={styles.container}>
<h2 className={styles.bigAmount}>
{data.thirdScreen[0] && data.thirdScreen[0].AMOUNT}
</h2>
</div>
);
}

Related

How do I fetch the data from the API? I always get Undefined

I'm practising React with a small project where I want to display some Nba players but I don't get any data when trying to map an object.
I'm using this Api: http://data.nba.net/prod/v1/2022/players.json
Here is the code:
import React, { useEffect, useState } from "react";
const Players = () => {
const url = "http://data.nba.net/prod/v1/2022/players.json";
const [players, setPlayers] = useState([]);
useEffect(() => {
getPlayers();
}, []);
const getPlayers = async () => {
const api = await fetch(url);
const data = await api.json();
//wrapping a object into a array
setPlayers([data].flat());
};
return (
<div>
<h3>Sacramento player info</h3>
<ul>
{players.map((player) => (
<li key={player.league.sacramento.id}>
{player.league.sacramento.firstName}{" "}
{player.league.sacramento.lastName}{" "}
</li>
))}
</ul>
</div>
);
};
export default Players;
I recreated your code on codesandbox and it works just fine. I use other approach on getting data thru fetch and changed http:// to https://
const Players = () => {
const [data, setData] = useState(null);
function getAPIData() {
fetch("https://data.nba.net/prod/v1/2022/players.json")
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error("ERROR (response not ok)");
})
.then((data) => {
setData(data);
})
.catch((response) => {
console.log("error");
});
}
useEffect(() => getAPIData(), []);
return (
data && (
<div>
<h3>Sacramento player info</h3>
<ol>
{data.league.sacramento.map((player) => (
<li key={player.personId}>
{player.firstName} {player.lastName}
</li>
))}
</ol>
</div>
)
);
};
working code: https://codesandbox.io/s/players-info-51gf1w

React variable value not replaced in api call

I am trying to use UseParam to get the id, i am trying to place it inside of my API request however when i console.log it the actual value doesn't go inside rather the text itself.
vesselComponents.js :
function VesselComponents() {
const { id } = useParams();
const api = async () => {
try {
const res = await axios.get(
// here
`http://127.0.0.1:8000/api/maintenance/${id}`
);
return res.data;
} catch (error) {
console.log(error);
}
};
console.log(api);
const { components, error, loading } = useSelector(
(state) => state.components
);
const dispatch = useDispatch();
useEffect(() => {
fetchComponents()(dispatch);
}, [dispatch]);
const getTreeItemsFromData = (treeItems) => {
return treeItems.map((treeItemData) => {
let children = undefined;
if (treeItemData.children && treeItemData.children.length > 0) {
children = getTreeItemsFromData(treeItemData.children);
}
return (
<TreeItem
component={Link}
to={`./info/${treeItemData.id}`}
key={treeItemData.id}
nodeId={String(treeItemData.id)}
label={treeItemData.name}
children={children}
/>
);
});
};
const DataTreeView = ({ treeItems }) => {
return (
<TreeView
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
>
{getTreeItemsFromData(treeItems)}
</TreeView>
);
};
return (
<div className="components-container">
<div className="components-items">
<DataTreeView treeItems={components} />
</div>
<div className="component-detail">
<Outlet />
</div>
</div>
);
}
export default VesselComponents;
This is how the console.log look like :
async () => {
try {
const res = await axios__WEBPACK_IMPORTED_MODULE_3___default().get( // here
`http://127.0.0.1:8000/api/maintenance/${id}`);
return res.data;
} catch (err…
Also if i wanted to make this call rather in my slice how would i go about exporting this specific ID that changes so i can use it there.
This is because you actually log the function, not the return value.
I suppose you want to fetch the maintenance id as the component mounts. I advice you to use useEffect for this case.
import { useEffect, useState } from 'react'; // above the component's class declaration
// and inside your component
const [api, setApi] = useState(null); // null by default
useEffect(() => {
const fetchMaintenance = async () => {
try {
const res = await axios.get(
// here
`http://127.0.0.1:8000/api/maintenance/${id}`
);
return res.data;
} catch (error) {
throw Error(error);
}
});
};
fetchMaintenance()
.then((api) => {
setApi(api);
})
.catch((error) => {
console.log(error);
});
}, []);
And by that you can use the value of api anywhere you like.
For example to log it
useEffect(() => {
console.log(api);
}, [api]);
or to render it on your view
return (
return (
<div className="components-container">
{JSON.stringify(api)}
<div className="components-items">
<DataTreeView treeItems={components} />
</div>
<div className="component-detail">
<Outlet />
</div>
</div>
);
}

Displaying fetched data from API

function App() {
const [todos, setTodos] = useState(null);
useEffect(() => {
const GetTodos = async () => {
try {
const { data } = await axios.get("api/orders");
console.log(data);
setTodos(data);
console.log(todos);
} catch (err) {
console.log(err);
}
};
GetTodos();
}, []);
return (
<div className="App">
<h1>hello</h1>
{todos?.map((todo) => (
<p key={todo.ID}>{todo.ID}</p>
))}
</div>
);
}
How can I make the data I got from the API display on the page, I can see that it works when I log it to the console but it doesn't show up on the page
Okay the problem is your data returns an Array of Arrays.
Because your data has just one array nested inside, we can just use it as the data hook, something like this:
setTodos(data[0]);
to understand, here is an example
You could do as below, calling setTodos(data[0]) in your try-catch, as your API seems to be returning an array with the data you want at position 0.
function App() {
const [todos, setTodos] = useState(null);
useEffect(() => {
const GetTodos = async () => {
try {
const { data } = await axios.get("api/orders");
console.log(data);
setTodos(data[0]);
} catch (err) {
console.log(err);
}
};
GetTodos();
}, []);
return (
<div className="App">
<h1>hello</h1>
{todos && todos.map((todo) => (
<p key={todo.ID}>{todo.ID}</p>
))}
</div>
);
}

Too many re-renders for component

I am trying to call a component that shows the details of a notification when the notification is clicked. However, I kept on getting an error of too many re-renders.
This is my Notifications code
This component calls the database to get the list of notifications and then sets the first notification as the default notification clicked.
const Notification = (hospital) => {
const [users, setUsers] = useState([]);
const [search, setSearch] = useState(null);
const [status, setStatus] = useState(null);
const [notifDetails, setNotification] = useState();
useEffect(async () => {
await axios
.get("/notifications")
.then((res) => {
const result = res.data;
setUsers(result);
setNotification(result[0]);
})
.catch((err) => {
console.error(err);
});
}, []);
return(
<div className="hospital-notif-container">
{filteredList(users, status, search).map((details, index) => {
for (var i = 0; i < details.receiver.length; i++) {
if (
(details.receiver[i].id === hospital.PK ||
details.receiver[i].id === "others") &&
details.sender.id !== hospital.PK
) {
return (
<div
className="hospital-notif-row"
key={index}
onClick={() => setNotification(details)}
>
<div className="hospital-notif-row">
{details.name}
</div>
</div>
);
}
}
return null;
})}
</div>
<NotificationDetails details={notifDetails} />
);
}
For NotificationDetails:
This function is triggered when a notification is clicked from Notifications. The error is said to be coming from this component.
const NotificationDetails = ({ details }) => {
const [loading, setLoading] = useState(true);
useEffect(() => {
if (Object.keys(details).length != 0) {
setLoading(false);
}
}, [details]);
if (!loading) {
return (
<>
<div className="hospital-details-container">
<h2>{details.sender.name}</h2>
</div>
</>
);
} else {return (<div>Loading</div>);}
};
What should I do to limit the re-render? Should I change the second argument of the useEffects call? Or am I missing something in my component?
I tried calling console.log from NotificationDetails and it shows that it is infinitely rendering with the data I set in axios which is result[0]. How is this happening?
Your problem should be in NotificationDetails rendering. You should write something like:
const NotificationDetails = ({ details }) => {
const [loading, setLoading] = useState(true);
useEffect(() => {
if (details.length != 0) {
setLoading(false);
}
}, [details]);
return (
<div>
{loading &&
<div className="hospital-details-container">
<div className="hospital-details-header">
<h2>{details.sender.name}</h2>
</div>
</div>
}
{!loading &&
<div>
<ReactBootStrap.Spinner animation="border" />
</div>
}
</div>
);
}
With return outside the condition statement.
EDIT
Now I noted that you have an async useEffect that is an antipattern. You should modify your useEffect in this way:
useEffect(() => {
(async () => {
await axios
.get("/notifications")
.then((res) => {
const result = res.data;
setUsers(result);
setNotification(result[0]);
})
.catch((err) => {
console.error(err);
});
})()
}, []);

How do use map function over array of objects in React

Having done the necessary to read the data using fetchAPI, I am having problems displaying the content because of the nature of the array.
import React, { useState, useEffect } from "react";
function Home() {
const [userData, setUserData] = useState([]);
async function getData() {
let response = await fetch("https://api.xxxxxxxx.io/something/students");
let data = await response.json();
return data;
}
//call getData function
getData().then((data) => console.log(data)); //
useEffect(() => {
getData()
.then((data) => {
setUserData(data);
})
.catch((error) => {
console.log(error);
});
}, []);
return (
<div>
{Object.keys(userData).map((item, index) => (
<div key={index}>{item}</div>
))}
</div>
);
}
export default Home;
When I checked the console, the data are displayed but it is only showing students with no other data displayed.
I have the data below.
Try the following changes:
const [userData, setUserData] = useState({ students: [] });
...
return (
<div>
{userData.students.map((item, index) => (
<div key={index}>{item}</div>
))}
</div>
);

Resources