I'm using react-google-recaptcha to generate invisible ReCaptcha and I need to use the token in another const.
The token is generating correctly, but I don't know how to pass it on to another location. How should I do this?
const onTextSubmit = async () => {
let recaptchaToken;
if (recaptchaLoaded) {
recaptchaToken = await recaptcha.current.execute();
}
// How to export recaptchaToken?
};
I need to get the recaptchaToken and use it here:
const onSubmit: SubmitHandler<FormInput> = (data) => {
formCreateMutation.mutate({
data,
recaptchaToken,
});
};
The two const are in the same file, I'm using react to do that.
Thanks!!
You are not posting all code from the component but you can store the recaptchaToken value in react state like this:
export default function App() {
const [recaptchaToken, setRecaptchaToken] = useState(undefined);
const onTextSubmit = async () => {
if (recaptchaLoaded) {
const value = await recaptcha.current.execute();
setRecaptchaToken(value);
}
// How to export recaptchaToken?
};
const onSubmit: SubmitHandler<FormInput> = (data) => {
if (recaptchaToken) {
formCreateMutation.mutate({
data,
recaptchaToken,
});
}
};
return (
<div className="App">
<h1>{recaptchaToken}</h1>
</div>
);
}
Related
I am noob on front-end world and could not find a solution for that I have a MainPanel component and I want to get data by using a service class method. The service class will have multiple functions and I will use them in different places.
Here is MainPanel code:
const [posts, setPosts] = useState({ blogs: [] });
const service = FetchCustomerService;
useEffect(() => {
const fetchPostList = async () => {
let customers = service.getCustomerList;
setPosts({ customers });
console.log(customers);
};
fetchPostList();
}, []);
And I want to create a separate service class for calls to backend:
export class FetchCustomerService {
getCustomerList = () => {
const { data } = await axios(
"https://jsonplaceholder.typicode.com/posts"
);
return data;
}
getAnotherFunction = () => {
}
}
export default FetchCustomerService;
How can I call service class method from MainPanel? There are some examples like giving the service class into main panel as props but isn't it possible to just call it like a Java class object etc calling like:
FetchCustomerService.getCustomerList();
You don't need a class for that, just export the functions you need from the file:
export async function getCustomerList() {
const { data } = await axios(
"https://jsonplaceholder.typicode.com/posts"
);
return data;
}
export function getAnotherFunction(){
...
}
import { getCustomerList } from 'yourFile';
...
useEffect(() => {
const fetchPostList = async () => {
const customers = await getCustomerList();
setPosts({ customers });
};
fetchPostList();
}, []);
I'm looking for a way to have a dynamic route that displays for every document in a Firestore collection using Server-side Rendering.
For example, a document called foo would exist at test.com/foo under the [doc] page component. Any time a document is added, it should be able to be accessed through its respective URL.
I've tried this method but I haven't been able to get it to work.
I've also tried implementing getServerSideProps but have not had much success, any pointers would be appreciated.
Code from the method above as follows:
under pages/api/[doc].js
export default (req, res) => {
db.collection("docs")
.doc(req.query.name)
.get()
.then((doc) => {
res.json(doc.data());
})
.catch((error) => {
res.json({ error });
});
};
under pages/[shoal].jsx
import { useRouter } from "next/router";
import useSWR from "swr";
const fetcher = async (...args) => {
const res = await fetch(...args);
return res.json();
};
function Doc() {
const router = useRouter();
const { name } = router.query;
const { data } = useSWR(`/api/${name}`, fetcher);
if (!data) {
return "Loading...";
}
return (
<div>
<p>Title: {data.title}</p>
</div>
);
}
export default Doc;
You can try using getServerSideProps:
export const getServerSideProps = async (ctx) => {
const doc = await db.collection("docs").doc(ctx.query.id).get()
const data = doc.data()
if (!data) return { notFound: true };
return { props: { data } };
};
function Doc({data}) {
const router = useRouter();
const { name } = router.query;
if (!data) {
return "Loading...";
}
return (
<div>
<p>Title: {data.title}</p>
</div>
);
}
export default Doc;
Simple solution.
const { data } = useSWR(api ? '/api/${name}' : null, fetcher);
Conditionally fetch the data if your variable is defined, if not, don't pass a URL string, better yet; you can conditionally consider the fetcher for usage also.
const { data } = useSWR(name ? '/api/${name}' : null, name ? fetcher : null);
While trying to use TMDB API in my project I ran into an issue that I am unable to figure out. I use copies of the same code as shown below in two different files and functions - one works, and the other one returned undefined for some reason. Can you please point out what I am not doing right, I need fresh new eyes on this. Thank you
import Head from 'next/head';
import React from 'react';
import { useState, useEffect } from 'react';
import Link from 'next/link';
import styles from '../styles/Home.module.css';
export const getServerSideProps = async () => {
const movieApi = process.env.TMDB_API_KEY;
const res = await fetch(`https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=${movieApi}&page=1`);
const movie_data = await res.json();
return {
props: {
movies : movie_data
},
}
}
const Form = ({movies}) => {
console.log(movies); //returns "Undefined"
const [search, Setsearch] = useState("");
//Handle input value
const getLocation = async (e) => {
// console.log(e.target.value)
e.preventDefault();
}
//Handle Submit
const handleSubmit = (event) =>{
// console.log("clicked")
event.preventDefault();
}
export const getServerSideProps = async () => {
const movieApi = process.env.TMDB_API_KEY;
const res = await fetch(`https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=${movieApi}&page=1`);
const movie_data = await res.json();
return {
props: {
movies : movie_data
},
}
}
export default function Home({movies}) {
console.log(movies); //works perdectly
const [session, loading] = useSession();
const tmdbMpviesResults = movies.results
As per your comment, <Form /> is not a page. Exactly that is your problem:
getServerSideProps can only be exported from a page. You can’t export it from non-page files.
Seems easy but I can't figure it out, how would you return the results from a function that's being imported to a component?
I get the correct results when i console log them from the .then() but can't seem to return them to the component.
example:
functions.js
export const getFeatures = (e) => {
let features = Client.getEntries({
content_type: '###',
'fields.type': `${e}`
})
.then(response => {
return response.items;
})
.catch(console.error)
}
Component.js
import {getFeatures} from './functions.js'
const App = () => {
let x = getFeatures('home');
console.log(x)
return ( ... )
// expecting the array response [{},{},{}, .. etc], but getting undefined instead
}
getFeatures doesn't return anything, you should change it to return its promise:
export const getFeatures = (e) => {
return Client.getEntries({
content_type: '###',
'fields.type': `${e}`
})
.then(response => {
return response.items;
})
.catch(console.error)
}
then at App add a features state, that will get updated when you call getFeatures on mount stage called by useEffect:
import { useState, useEffect } from 'react'
import {getFeatures} from './functions.js'
const App = () => {
// create a features state
const [features, setFeatures] = useState([])
// on mount call 'getFeatures'
useEffect(() => {
getFeatures('home')
.then(setFeatures) // chain returned promise and pass setFeatures to update features
}, []) // add empty array to tell to run the code on mount only
// do some mapping with features, this is for example purpose
// remember to add an unique key to each feature
return ( features.map(feature => {
return <div key={feature.id}>{feature.name}: {feature.realease}</div>
}))
}
getFeatures('home') will return undefined instead of response.items in your code.
Try this:
// functions.js
export const getFeatures = async (e) => {
const resp = await Client.getEntries({
content_type: '###',
'fields.type': `${e}`
})
return resp.items;
}
// App.js
import {getFeatures} from './functions.js'
const App = () => {
getFeatures('home').then(x => {
console.log(x);
// do something else
});
return ( ... )
}
I've made a really simple React hook. That's something seen on many guides and websites:
import { useEffect, useState } from 'react';
import axios from 'axios';
export const useFetchRemote = (remote, options, initialDataState) => {
const [data, setData] = useState(initialDataState);
useEffect(() => {
const fetchData = async () => {
const result = await axios.get(remote, options);
setData(result.data);
};
fetchData();
}, [remote]);
return data;
};
Example usage:
import { useFetchRemote } from '../utils';
export const UserList = () => {
const users = useFetchRemote('/api/users', {}, []);
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>}
</ul>
);
}
This is working. If I understand correctly:
With no dependencies like useEffect(() => { /*...*/ }), setting the state into the function would trigger a re-render, calling useEffect again, in an infinite loop.
With empty dependencies like useEffect(() => { /*...*/ }, []), my function will be called only the "very first time" component is mounted.
So, in my case, remote is a dependency. My function should be called again if remote changes. This is true also for options. If I add also options, the infinite loop starts. I can't understand... why this is happening?
export const useFetchRemote = (remote, options, initialDataState) => {
// ...
useEffect(() => {
// ...
}, [remote, options]);
// ...
};
The infinite loop is caused by the fact that your options parameter is an object literal, which creates a new reference on every render of UserList. Either create a constant reference by defining a constant outside the scope of UserList like this:
const options = {};
const initialDataState = [];
export const UserList = () => {
// or for variable options instead...
// const [options, setOptions] = useState({});
const users = useFetchRemote('/api/users', options, initialDataState);
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>}
</ul>
);
}
or if you intend the options parameter to be effectively constant for each usage of the userFetchRemote() hook, you can do the equivalent of initializing props into state and prevent the reference from updating on every render:
export const useFetchRemote = (remote, options, initialDataState) => {
const [optionsState] = useState(options);
const [data, setData] = useState(initialDataState);
useEffect(() => {
const fetchData = async () => {
const result = await axios.get(remote, optionsState);
setData(result.data);
};
fetchData();
}, [remote, optionsState]);
// ---------^
return data;
};
This second approach will prevent a new fetch from occuring though, if the options are dynamically changed on a particular call site of useFetchRemote().