useRouter not working inside getInitialProps - reactjs

I am trying to get data from the API by using POST Method, However, I am struggling to set the data into post
import { useRouter } from 'next/router';
import Layout from '../../components/MyLayout';
import Settings from '../../components/Settings';
const Post = props =>{
//works if I use here
const router = useRouter();
return (
<Layout>
<h1>{router.query.id}</h1>
<p>This is the blog post content.</p>
</Layout>
);
}
export default Post;
Post.getInitialProps = async function(){
//trying to get data ($_GET)
const router = useRouter();
const data = router.query;
//
const FormData = new URLSearchParams();
const res = await fetch(Settings.api+'viewPost',{
method: 'POST',
headers:{
'Content-Type': 'application/x-www-form-urlencoded',
},
body: FormData,
});
const obj = await res.json();
return(
obj
);
}
I receive this following error
Invalid hook call. Hooks can only be called inside of the body of a
function component. This could happen for one of the following
reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app See *** for tips about how to debug and
fix this problem.
I just learn about this, sorry for the dumb question. I really appreciate any answer. Thank you.

I did the exact same thing (try to use useRouter in getinitialProps) as you and get the same error just now, then I search around and found how to get query string parameter in next , so to answer your question , you don't need useRouter in this case but instead use getInitialProps (props) and find the query params to get your data or Id or whatever. Hope that helps.
Post.getInitialProps = async function({ query }){
const { data } = query;
...................
}

Related

React Query does not work with Astro Framework

I'm trying to use React-Query with Astro to fetch data from my Django Rest Framework backend. Astro has been a great way to organize my react-based frontend but I am worried it might not be compatible with React-Query.
Whenever I try to make a query to my backend I get an 'isLoading' value of true (and an isError of false). I never manage to recover the data from my endpoints however.
I have been following a variety of tutorials with the same results. Here is the code where I'm stuck:
import { QueryClient, useQueryClient, QueryClientProvider, useQuery } from '#tanstack/react-query';
import { gettestApi } from "../../api/testApi";
function MyComponent(props) {
const queryClient = useQueryClient();
const {
isLoading,
isError,
error,
data: test
} = useQuery('test', gettestApi)
let content
if (isLoading) {
content = <p>Loading...</p>
} else if (isError){
content = <p>{error.message}</p>
} else {
content = JSON.stringify(test)
}
As you can see, I import an axios function from /api/testAPI.js which looks like this:
import axios from "axios"
const testApi = axios.create({
baseURL: "http://127.0.0.1:8000"
})
export const gettestApi = async () => {
return await testApi.get("/api/endpoint/").then(response => response.data)
}
That's how most tutorials I have seen and the official documentation wrap up their examples, however my backend server which should be triggered by this endpoint records absolutely no hits from react-query, which is curious to me. I understand that nothing 'calls' my react-query or my gettestApi() function, but it seems to be unnecessary for other people to retrieve their data.
Maybe it would be useful to point out that contrary to other framework with React, Astro does not have an App.js root to surround with
<QueryClientProvider client={client}>
<App />
</QueryClientProvider>
Instead, I have added these QueryClientProvider brackets to the highest React component I could.
I feel like I'm missing some intuition about Tanstack Query/ React-Query. Could anybody point me in the right direction? Thanks a lot for the help.
From what I've seen in the astro docs:
The most important thing to know about Astro components is that they render to HTML during your build. Even if you run JavaScript code inside of your components, it will all run ahead of time, stripped from the final page that you send to your users. The result is a faster site, with zero JavaScript footprint added by default.
So it seems all react code only runs on the server, where data fetching via useEffect or useSyncExternalStore subscriptions just doesn't run. But this is exactly what react-query is doing, so yeah I think they don't work well together. I'm also not sure what the purpose of react-query in a setting would be where there is no client side javascript.
You can set client:only on your Astro component so the React component doesn't run on the server. There are shared-state limitations but still React Query feels better than just fetch + useEffect + own-code even if its not in a complete React app. In this example I'm also using an init function that reads cookies from the client's browser which is another case for when to use client:only.
Astro:
---
import Layout from "../../layouts/Layout.astro";
import ClientPanel from "../../components/client/ClientPanel";
---
<Layout title={ 'Client' }>
<ClientPanel client:only></ClientPanel>
</Layout>
React:
// imports
const queryClient = new QueryClient()
/** client:only component */
const ClientPanel = () => (
<QueryClientProvider client={queryClient}>
<ClientData />
</QueryClientProvider>
)
const ClientData = () => {
const { getUser, getSession } = useSession(); // read cookies functions
const [ user, setUser ] = useState(getUser);
const { isLoading, error, data } = useQuery({
queryKey: ['patientData'],
queryFn: () => getSession() // validate or refresh token
.then(session => fetchPatientData(session.tokens.token))
.catch(error => error === 'INVALID_SESSION' ? null : undefined)
})
if (!user || data === null) window.location.replace('/login')
// return statement, etc.

Remix loader returning "undefined"

I am giving remix a good first-time try and I think I love its approach to data handling. However, I am facing an issue with data returning "undefined" from the loader wrapper.
import { LoaderFunction } from "#remix-run/node";
import { useLoaderData } from "#remix-run/react";
import axios from 'axios';
const url = 'https://jsonplaceholder.typicode.com/users'
export async function Members(){
const {data} = await axios.get(url);
return data
} //I am sure it returns the expected data when I call on this function.
export const loader: LoaderFunction = async () => {
const response = await Members()
return response
};
export const Architects = () => {
const members = useLoaderData()
console.log(members)
return (
....
)
}
What am I really missing here? I'll appreciate a pointer here. It wouldn't be wise to use other react based approaches that isn't remix's
This isn't even an issue but a misappropriation in writing the methods.
For anyone who might make this kind of silly mistake, please, do ensure you are calling these remix helpers in your ROUTES.
It will not work in any of your components files just like I tried to do it.
The loader and useLoaderData and most of the remix's methods are mostly serverside. Nothing is wrong with the above code. Where I called it is what the problem was.
Thanks to all those who viewed this.
I would also like to point out that LoaderFunction should be imported like this:
import type { LoaderFunction } from "#remix-run/node";

After pushing hook useHistory I get ' Warning: React has detected a change in the order of Hooks called by ...'

I am in a page localhost:8080/authors/1
I do a post and as I post I get a new id 2.
With this new id I want to jump to the page localhost:8080/authors/2 from localhost:8080/authors/1.
in AuthorForm:
import {useHistory} from 'react-router-dom';
const history = useHistory()
const onSubmit = async data => {
const response = await onUpdateData({author: data});
history.push(`/authors/${response?.data?.createAuthor?.id}`);
}
on localhost:8080/authors/:id I use useParams() to get the id
const authorId = useParams()?.id;
const { loading, error, data } = useQuery(fetchAuthor, {
variables: {id: authorId} })
if(loading) {
return(<div> Loading </div>)
}
if(error) {
return(<div> error </div>)
}
return (<AuthorForm initialValues={formTranslator(data)}/>);
}
After pushing hook useHistory I get 'react_devtools_backend.js:2430 Warning: React has detected a change in the order of Hooks called by 'x'. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks'
I found hard to work with apollo useQuery.
Using ApolloClient instead and useEffects the issues disappeared, from now on I will be very careful when working with useQuery.
The solution was to add skip to useQuery

Why is fetching data in next.js with hardcoded api-key working but not with environment variable?

I followed the documentation of Next.js, so I created a file called .env.local and stored my API key inside.
When console.logging that key it gets shown in the server-console and not in the browser console. So far I understand this.
Problem: I want to fetch some data from the given URL. How can I get this done, without giving my API_KEY to the browser?
I think that topic is quite confusing for beginners (as me) and I an many other (so I think) would be overjoyed if anyone could get the confusion out of that.
Here is my code: (If I hardcode my API_KEY inside the URL it works fine)
import Haversine from '../components/Haversine'
import LangLat from '../components/LangLat'
import axios from 'axios'
import { useEffect } from 'react'
const key = process.env.API_KEY
const index = () => {
console.log(key)
const getLangLat = async () => {
try {
const response = await axios.get(
`https://geocode.search.hereapi.com/v1/geocode?q=wimpfener str 40 backnang&apiKey=${key}`
)
console.log(response.data)
} catch (err) {
console.error(err.message)
}
}
useEffect(() => {
getLangLat()
})
return (
<div>
<Haversine />
<LangLat />
</div>
)
}
export default index
You need to add NEXT_PUBLIC_ to the beginning of your environmental variable so you have access to it on the client side.
So inside of your .env.local change
API_KEY to NEXT_PUBLIC_API_KEY and do the same inside of your code.
https://nextjs.org/docs/basic-features/environment-variables#loading-environment-variables

Problems with react to translate words using google translate api

I am trying to create a translation page where you type the word and it should translate to the language you chose in the dropdown. Using React and axios and the API from Rapid API.
I keep getting error like 401, 429 I know what the errors are but don't know how to fix it. Could it be from the website [Rapid API][1] that gives me a bad API?
import axios from "axios"
// de-structure language and text props
const Convert = ({ language, text }) => {
const [results, setResults] = useState("")
useEffect(() => {
const translate = async () => {
const translation = await axios.post(
"https://google-translate1.p.rapidapi.com/language/translate/v2",
{},
{
params: {
q: text,
target: language.value,
key: "cd4662825bmshfb23e36cc668d7fp111f42jsn736f6cc3a9aa",
},
}
)
setResults(translation.data.data.translations[0].translatedText)
}
translate()
}, [language, text])
console.log(results);
return (
<div>
<p>{results}</p>
</div>
)
}
export default Convert ```
[1]: https://rapidapi.com/googlecloud/api/google-translate1?endpoint=apiendpoint_a5764907-04b6-4d61-869b-79dc5325c739
I think there are 2 different APIs here... You are talking about the RapidAPI API but in the code you are using the MyMemory API.
So, regarding to your code and the MyMemory API specification, I see a couple errors in your code:
You are calling the /status endpoint, which checks the status of a TM import. I think this is not the endpoint you want to call. Instead, you have to make the request to the /get endpoint: https://api.mymemory.translated.net/get.
Also the request should be a get, not a post (just replace axios.post with axios.get).
The "q" and "key" params are correct, BUT in the documentation it says that you have to send a "langpair" param, not a "target".
With those changes the code should go fine. I've tried it and it works.
Try the next code:
import React, { useState, useEffect } from "react"
import axios from "axios"
import qs from "qs"
// de-structure language and text props
const Convert = ({ language, text }) => {
const [results, setResults] = useState("")
useEffect(() => {
const translate = async () => {
const translation = await axios.post(
"https://google-translate1.p.rapidapi.com/language/translate/v2",
qs.stringify({
q: text,
target: language.value
}),
{
headers: {
'x-rapidapi-key': 'cd4662825bmshfb23e36cc668d7fp111f42jsn736f6cc3a9aa',
'x-rapidapi-host': 'google-translate1.p.rapidapi.com'
}
}
)
setResults(translation.data.data.translations[0].translatedText)
}
translate()
}, [])
console.log(results);
return (
<div>
<p>{results}</p>
</div>
)
}
export default Convert
If you get a 403 Forbidden error then it's possibly because you're not subscribed to the API. To fix this, just go to https://rapidapi.com/googlecloud/api/google-translate1 and click on the "Subscribe to Test" button. Then select the free plan and you will be ready to go.
Here are some points that can definitely solve this issue.
If you're using RapidAPI then x-rapidapi-key is your API key. So instead of mentioning key in params, you can pass x-rapidapi-key inside the headers.
The possible reason for the 403 code is that you're not subscribed to that particular API. Make sure to double-check that.
429 status code indicates so many request in the give amount of time. I have checked, the rate limit is 5 request per second for Google Translate API.
You can use the code snippet that RapidAPI provides in order to avoid any kind of unwanted errors.

Resources