How to add google recaptcha in create react app? - reactjs

I'm trying to get the recaptcha response so that I can pass along it via redux-form.
Have tried the 2 methods below...
Attempt 1:
Specifying callback in <head>.
index.html:
<script src='https://www.google.com/recaptcha/api.js?onload=callback&render=explicit'></script>
The problem here is that the callback is in global scope but I need to access it in React components.
Attempt 2:
Specifying callback in DOM.
Component: handleRecaptcha(resp)
handleRecaptcha(resp) {
console.log(resp);
}
Component: render():
<div className="g-recaptcha" data-callback={this.handleRecaptcha.bind(this)} data-sitekey="***"></div>
index.html:
<script src='https://www.google.com/recaptcha/api.js'></script>
I get the message ReCAPTCHA couldn't find user-provided function: function () { [native code] } after submitting the recaptcha. Probably a scope problem too.
I'm trying to avoid using another library, since I think this is a rather trivial problem.
Would anyone happen to have any idea how to go about it?
All I need is to get hold of the widget instance, and do grecaptcha.getResponse(widget) to get the response. API ref

Use react-recaptcha
import Recaptcha from 'react-recaptcha'
<Recaptcha
sitekey="xxxxxxxxxxxxxxxxxxxx"
render="explicit"
verifyCallback={verifyCallback}
onloadCallback={callback}
/>

You could also try Reaptcha.
It is a lot cleaner, more modern and has more of a React-way approach in handling the reCAPTCHA widget.
<Reaptcha
sitekey="YOUR_API_KEY"
onVerify={() => {
// Do something
}}
/>

Related

Dynamic form only shown on refresh

I've been having an issue where the client has provided me a third party Marketo form to include on one of the pages I'm building out which works on a "normal" html page when testing locally, however on Gatsby, it's not working. The script that was provided is as follows:
<script src="//app-xxxx.marketo.com/js/forms2/js/forms2.min.js"></script>
<form id="mktoForm_xxxx"></form>
<script>MktoForms2.loadForm("//app-xxxx.marketo.com", "xxx-xxx-xxx", xxxx);</script>
I've added the top script tag into gatsby-ssr.js like so:
import React from 'react'
export const onRenderBody = ({ setPostBodyComponents }) => {
setPostBodyComponents([
<script
key="mktoForm_test"
src="//app-sjst.marketo.com/js/forms2/js/forms2.js"
/>,
<script
key="/js/site.js"
src="/js/site.js"
/>
])
I've added the following to /static/js/site.js to initialize the form:
MktoForms2.loadForm("//app-xxx.marketo.com", "xxx-xxx-xxx", xxxx);
Then, on the page where I want the form, I've added this:
<form id="mktoForm_xxxx"></form>
The form only displays when I'm on the page and manually refresh the browser. Clicking into the page from any other page does not render the form at all. I'm guess it's how Gatsby/React routes to the page with the form.
Can someone please help??
You probably need to call that .loadForm function when the component that has that form mounts.
React.useEffect(() => {
// load form here...
}, []
If it's just being called in site.js, it's probably being called before the form element is present in the DOM so it has nothing to attach to.
I created this example a while ago, leaving it here in case it's extra help: https://github.com/CharlieDieter/react-marketo-hook

React onClick not working in any of my browsers, but for colleagues it does

I've created an onClick handler in a very simple React function component:
export default function MyButton() {
return (
<button
onClick={() => {
console.log('test');
}}
>
Button
</button>
);
}
Now the weird part: no matter what browser I use, the event is not firing. I've created such a component hundreds of times and everything was good, until now.
For everyone else this code works, as it was intended.
I cannot share the whole project or an example repository. It's really nothing but a simple React app you see everywhere.
What could be the reason for why it's not working on my system?
EDIT:
The error was somehow within yarn. I called webpack-dev-server -d source-map --mode=development for development and I am using "webpack-dev-server": "^4.0.0-beta.0". I think the cache could've gotten corrupted somehow.
To fix it, I removed my output directory and started the script with npm instead of yarn. This way it worked, even when I use yarn again.
I really don't know why this happened. Would be happy to know why.
I also faced the same issue and the reason of the issue (in my case , probably yours ) is HtmlWebpackPlugin, HtmlWebpack Plugin is adding a addition script tag of bundle in head tag of index.html.
my html
<html>
<head>
<title>my-react-app</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
htmlwebpackplugin generated html
<html>
<head>
<title>my-react-app</title>
<script defer src="bundle.js"></script></head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>
</html>
because of this additional script tag, there was a problem in react (i read a post on reddit regarding to this problem and he also have multiple script of same bundle and he was having the same problem), i solved it by deleting my script tag, but we can use copywebpack plugin to just copy html. Or other solution is to configure htmlwebpackplugin suck a way that it will not inject any addition tags
...
new HtmlWebpackPlugin({
name: "index.html",
inject: false,
template: path.resolve(__dirname, "public/index.html"),
}),
...
Use named function instead of anonymous function. Named functions are very useful for identifying what functions caused errors during development as well as when retrieving logs from your users.
import React from "react";
export default function MyButton() {
const handleChange = () => {
console.log("test");
};
return <button onClick={handleChange}>Button</button>;
}
It is a good practice to name-all-functions for a better developer debugging (and development) experience which anonymous function does not provide.
For more clarification between Named and Anonymous function Learn the benefits of Named vs Anonymous function here
Try typing your function as React.FC.
Create a typescript (tsx) file and use the upcoming code:
import React from "react";
export const MyButton: React.FC = () => {
return (
<button
onClick={() => {
console.log("test");
}}
>
Button
</button>
);
};
Note that using this code, you are typing the component making sure that your function is typed as React.FunctionComponent.
Did you import this in your file, if not then add this tine on top
import React from 'react';

Which moment does React import my JS file?

In React, the imported JS code is read before rendering the HTML, right?
If I want to add an EventListener to an element, I'll always have to do it on the body (or document) load? Would I always need to create a function and attribute it to the <body onLoad="fnOnLoad"> or document.addEventListener("DOMContentLoaded", "fnOnLoad", true); ?
I'm asking this because if you use plain HTML and add the script in the end of the <body> section, It'll add the event to the element without me having to add it "on Load" of something, right?
If you are using something like create-react-app, you only need to add event attribute to the element:
<Element onClick={//your code} />
or
<Element onChange={//your code} />
Check the docs here: https://reactjs.org/docs/events.html
componentDidMount and componentWillUnmount methods will do your tasks.
componentDidMount: When the component is mounted, add your DOM listener
componentWillUnmount: Make sure to remove the DOM listener when the component is unmounted
Following link might be Helpful for you.
https://linguinecode.com/post/react-onclick-event-vs-js-addeventlistener

Cloudinary openUploadWidget throw error in my react app

I seem not to be doing something right, but I don't know what. I need to open cloudinary upload widget in my web app and it keeps throwing this error; TypeError: __WEBPACK_IMPORTED_MODULE_6_cloudinary___default.a.openUploadWidget is not a function.
I am using react and this is how I am using it...
load = (e) => {
e.preventDefault();
cloudinary.openUploadWidget({ cloud_name: 'classvideo', upload_preset: 'classVideo' },
function (error, result) { console.log(result) });
}
This is how I tried rendering it on the click of a button inside my render method...
<div>
<button onClick={this.load}>upload Image</button>
</div>
and this is the script tag in my html
<script src="//widget.cloudinary.com/global/all.js" type="text/javascript" />
<script src='//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script>
Is there something I'm doing the wrong way? what does webpack have to do with this?
please help
Try adding window.cloudinary.openUploadWidget({..
cloudinary will be a global object if you are loading it with a separate script tag.
If you remove your import that shadows the global object it will work as expected.
// import cloudinary from 'cloudinary';
If you are landing on this post but are using Angular instead, note that you have to:
include the script in angular.json
reference the script from index.html
...and then declare the cloudinary variable in the component
Notice that I am not using the remote script reference but have downloaded the widget source code and have included it in my project.
You can use React Cloudinary Uploader for Rect, it's a good solution at this time to handle Cloudinary in React.

How to solve double API fetch on universal ReactJS

In current setup, I'm building multi-page universal web application (using react-router to do routing on both server and client). This project doesn't use any (redux) store (which I consider unneccessary for now).
One of component responsible for fetch data from remote API, done inside componentWillMount method.
When render on server, the component will fetch data, do rendering and send rendered HTML to client.
When client mount HTML with ReactJS, it fetch data once again from componentWillMount method. That's cause unneccessary double data fetch.
Does it have any solution?
Thanks for answer from Dominic Tobias.
I tried develop a couple solution but I found one that suitable for me.
First, I decided not to fetch data either in componentWillMount or componentDidMount inside component, but create a static method call fetchData which return Promise like this:
class PageContainer extends Component {
static fetchData(params) {
return fetch('...URL...')
}
render() {
const {data} = this.props;
//render logic here
}
}
and on server side, call PageContainer.fetchData and wait until promise is fulfilled, pass data as props to PageContainer and render HTML with hydrated data like this
<html>
<head></head>
<body>
<div id="roor">{..react rendered HTML..}</div>
<script>window.__DATA__ = {..data..}</script>
</body>
</html>
like I said, for this app, I think that redux is unnecessary for now.
Then, there is a problem on client side routing which is react-router cannot load async data. To fix that, I went looking for AsyncProps and write my own tiny version of that, called AsyncComp. You can bootstrap React on client side with react-router like this:
const Root = <Router history={browserHistory} routes={routes} render={(props) => <AsyncComp {...props} data={window.__DATA__}/>}/>
ReactDOM.render(Root, document.getElementById("root"));
That's all.
PS. After I built AsyncComp, it can also be used on server side like this:
AsyncComp.fetchData(routerProps)
.then((data) => {
const html = ReactDOM.renderToString(<AsyncComp {...routerProps} data={data}/>)
res.render('index', { html: html, data: data })
})
Since your data already exists you should have a function which will make a conditional fetch which you can call on both the server and componentDidMount (you're not supposed to make ajax calls in componentWillMount).
For example this is how a component looks for me using redux:
class User extends Component {
static readyOnActions(dispatch, params) {
return Promise.all([
dispatch(UserActions.fetchUserIfNeeded(params.id))
]);
}
componentDidMount() {
User.readyOnActions(this.props.dispatch, this.props.params);
}
If this is the current page then the server will call the readyOnActions, and on the client componentDidMount can call the same thing - the action called fetchUserIfNeeded will only make an AJAX request if the server hasn't already done it by checking if the data already exists (and you can add further checks such as if it's valid, if it's not already fetching etc).

Resources