Invalid hook call trying to make an axios get request in react - javascript

I'm recreating a simple weather app with react and am having a lot of trouble creating a very simple API call. I've tried a plethora of methods on here, youtube, etc and continuously get errors. The current code I have is:
import Axios from 'axios';
import { Home } from '../components/Home'
import React, {useState, useEffect} from 'react'
var weatherApiRootUrl = 'https://api.openweathermap.org';
var weatherApiKey = 'd91f911bcf2c0f925fb6535547a5ddc9';
//function to generate weather URL. fetches lat/lon and creates new url
function GetWeatherUrl(loc){
const [weatherLink, setWeatherLink] = useState("");
const getCoordinates = () => {
Axios.get(`${weatherApiRootUrl}/geo/1.0/direct?q=${loc}&limit=5&appid=${weatherApiKey}`).then(
(response)=>{
console.log(response);
setWeatherLink(`${weatherApiRootUrl}/data/2.5/onecall?lat=${response.data.lat}&lon=${response.data.lon}&units=imperial&exclude=minutely,hourly&appid=${weatherApiKey}`);
}
);
};
return(
<div>
{weatherLink}
</div>
);
}
export{
GetWeatherUrl
}
The purpose of this file is just to use the user input (a city name designed by variable loc) to fetch lat/lon coordinates of the inputted city as that data is needed for the second link that fetches weather information. The user input is handled from another component and works fine.
All I intend for this code to do is fetch latitude and longitude data using loc and use those numbers to generate the new link that fetches weather data. The weather data will be done with a different api call on another file. The working method of this current file should be useable for the future file meant to fetch weather so this is kind of two birds in one stone.
I need the weatherLink generated to be able to be exported to do this so I would really prefer a solution allowing that please. I originally was going to just export the raw lat/lon data and use them for the call in the new file as how I did with loc here but I decided returning a completed link as a string would maybe be easier. Really would appreciate someone's help on this it's been frustrating me for way longer than it should!
Not really needed but here's the non-react version of the site if it helps: https://giovannimalcolm.github.io/weather-dashboard/

This can be easily solved without needing to use React at all, since it is not a component and doesn't have any rendering logic in itself per se:
import Axios from 'axios';
const weatherApiRootUrl = 'https://api.openweathermap.org';
const weatherApiKey = 'd91f911bcf2c0f925fb6535547a5ddc9';
export async function GetWeatherUrl(loc) {
const response = await Axios.get(`${weatherApiRootUrl}/geo/1.0/direct?q=${loc}&limit=5&appid=${weatherApiKey}`);
return `${weatherApiRootUrl}/data/2.5/onecall?lat=${response.data.lat}&lon=${response.data.lon}&units=imperial&exclude=minutely,hourly&appid=${weatherApiKey}`;
}
Then in places where you need to use the weather URL, you need to remember that GetWeatherUrl returns a promise, so you've got to await it (or handle it like any other promise):
const myFn = async () => {
const weatherUrl = await GetWeatherUrl(loc);
const weatherUrlData = await Axios.get(weatherUrl);
};
myFn();

Related

useContext giving me undefined value on different components after setting that value

I am creating a context for a log in, so after creating the context I wrap all my routes with that context.provider and send the initial value to each child, which in my case is a useState:
<userContext.Provider value={{loggedUser, setLoggedUser}}>
I have a component LogInMenu.jsx that basically sets the loggedUser (loggedUser has a username/password structure) to a valid user. I consume the context in LogInMenu.jsx like this:
const { loggedUser, setLoggedUser } = useContext(userContext)
After succesfully console logging the loggedUser value in LogInMenu.jsx (just to make sure it was correct) I go to my other component called Dashboard.jsx and consume the context there the same way as I consumed it in LogInMenu.jsx, but this time, If I console log the loggedUser it gives me undefined value.
Note: I have imported useContext hook in each of the components that use it like this:
import React, { useState, useContext } from 'react';
and the context I created like this:
import { userContext } from './App';
If you need more code to understand the issue I can provide it.
I was going thru the code sandbox example, few points to consider
try moving the code inside the submit event handler
const submitData = async (e) => {
e.preventDefault();
// Ideally use post instead of get
// pass user id and password to Api
// password should never be stored in plain text in backend
// depending on the backend store it as hash and authenticate
// user Id/name and password in the backend
const loginResponse = await axios.get(`http://localhost:8002/users/${user}`)
if (loginResponse.isSuccess) {
setLoggedUser(loginResponse.userInfo)
}
};
You can get a good idea about React with their new documentation.
Cheers

How to properly Populate a Dropdown with SQL Query Values in React.Js Hook

I have a react component called Sidebar.jsx. Within it, I am making an API call to get a array of fleets to populate an eventual JSX dropdown element within my Sidebar. This results in a simple JSON array.
I have imported a function called getFleets() from my services folder to make the API call. The service uses the fetch API to make a query call to my backend and looks like this:
export async function getFleets() {
const resp = await fetch("http://localhost:5000/fleets", {
method: 'GET',
headers: {},
mode: 'cors'
});
return resp.json();
};
However, when I use the website, it appears to infinitely make the API call. This is my first time trying to make an API call within a react component so I am a bit confused here. Other guides I've read online seem to be similar but I am obviously missing something.
What can I do to make this API call only once and retrieve my JSON array such that I can later use it to populate the options in my return ?
Sidebar.jsx
import React, { useEffect, useState } from "react";
import { getFleets } from "../services/FleetService";
const Sidebar = () => {
const [data, setData] = useState([]);
useEffect(() => {
const setFleets = async () => {
const fleets = await getFleets();
console.log(fleets);
setData(fleets);
}
setFleets();
}, [data]);
return (
<>
// Add data to <select> </select>
);
};
The way your code works, since data is part of the dependency array sent to useEffect, every time data changes the effect runs, which changes data, which runs the effect again ...resulting in the infinite loop.
The simple fix is to remove data from the dependency array, and explicitly specifying an empty array [] as the second parameter of useEffect. This will make the effect run only exactly once, when the component is first rendered.
You need to explicitly specify an empty array because when the second parameter isn't specified at all, the effect will run on every render, bringing back the infinite loop issue.

getServerSideProps proper usage?

I have recently been trying to create a web app with NextJS. I know some basics in web development but I was a little lost when using NextJS as I didn't do any React either before.
I've tried fetching data from an API and using this data in my page. I struggled a bit but in the end I got it working with the help of getServerSideProps.
My question is, how could I use getServerSideProps multiple times in my application so that I can fetch many other routes ? I've tried using getServerSideProps in a different file, using its response in a function that I then export as a component and use it so I can "get components of getServerSideProps responses" if it makes sense, but had many different errors when trying to do so.
Could someone explain how it actually works and how I could resolve my issue, and if it doesn't work that way, how could I make it work?
Here's an example using Coinbase's API :
import { useState } from 'react'
import fetch from 'isomorphic-fetch'
export const getServerSideProps = async () => {
const res = await fetch('https://api.coinbase.com/v2/prices/ETH-USD/buy')
const data = await res.json()
return {
props: {
ethprice: data
}
}
};
I then use "ethprice" in my Home function such as :
export default function Home({ ethprice }) {
return (
[page content, divs, text etc...]
{etherprice.data.amount}
Thanks!
getServerSideProps is specific to that particular file, you can't just use it in any way you want.
const Example = (props) => {
return // this is your component
}
export const getStaticProps = async () => {
// this will provide props specifically for 'Example'
}
More than that getStaticProps will only be run once on static page generation and never again, along with fetching the props for that particular component only. So you can't get live data from it, only data required to generate the page (like page title).
You can have a look at getServerSideProps if you're looking for something more dynamic that can fetch props at runtime. After that you can pass those props down to children if you need to.

I use next.js and i try to do a single post page

i use nextjs and i fetch some dummy data on home and now i want to make a page for each post that i got on home i made it but i feel is not a good code so if someone can healp me clear some things and also learn more on next i will appreciate this a lot. here is the code:
import { useRouter } from 'next/router'
import {useEffect} from 'react'
const post = () => {
const router = useRouter()
const pid = router.query.pid
async function getdata (){
if(pid){
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${pid}`)
const data = await res.json()
console.log(data)
}
}
useEffect(() => {
getdata()
}, [pid])
return(
<p>wasd{pid}</p>
)
}
export default post
I suppose you're talking about making components or each different route for each different data.
FIRST CASE-If we talk about the first case you can have a folder called components outside your pages for folder and make components there and map that component depending on your data or whatever.
SECOND CASE-If you want to have a different route [filename].js is the way to go this represents lets say localhost:3000/foldername/:filename. So you can do stuff from here. I'd suggest reading nextjs docs for more info on this routing.

Can I use axios in this example?

I'm still new to web development so I'm really sorry if the answer is obvious or the information provided by me is not much, but I hope this is sufficient:
Can I make an axios.post request within this vue.js component?
<script>
module.exports = {
mounted() {
// game code
};
</script>
Let me explain the problem I'm having at this moment: I can't import axios by import axios from "axios";. I neither can use export default { ... }. Both result in the page not loading (giving me an TypeError: "exports" is read-only). However, I need to access a variable within the gamecode since I want to axios.post that said variable (game score plus some more json info) to my MongoDB database.
If I can't make the request from there, am I able to get a variable from that code in mounted() { // game code }; and pass it to another component (and post it from there)? I searched the Internet for many hours but nothing seems to work for me, so again, sorry if it seems like I'm just too lazy to search for answers.
I managed to use axios within the module.exports part of the code.
Normally I would use import axios from 'axios'; and use axios as a method within
export default {
...
methods: {
// here (axios method)
...
But the
module.exports = { mounted() {
// game code
};
part did not work if I used the export default code part. I'm almost sure there is a more elegant way to solve this whole problem, but since I'm new and still don't understand totally how Vue and axios works, I simply tried some possibilities to include axios there and one worked:
module.exports = { mounted() {
const axios = require("axios");
// game code
// and later, for example: axios.post(...)...
};
At first I thought it wouldn't work since my IDE did not recognize the axios methods, but it actually posted data to my DB, so it did work.

Categories

Resources