Open Manuel-Manoury opened 6 years ago
Can you show an example of how you use it inside an iframe? But it seems like the google script would need to be loaded inside the iframe too.
Hi !
Here are the informations I find relevant:
I'm working on a widget, a bit like Intercom, which is intended to be loaded on a client website through very few operations. In order to avoid messing up the client CSS, I'm setting up my widget in an iframe
through the use of react-frame-component. I do have some amount of control on what's present in the rendered iframe
through the props head
and initialContent
(which I already use to embed inline CSS to avoid the client having to include the CSS file by himself).
I got rid of quite a lot of code for readability, but here is the idea:
import React from 'react';
import ReCAPTCHA from 'react-google-recaptcha';
import WidgetFrame from 'react-frame-component';
import { ConnectedRouter } from 'react-router-redux';
import { Route } from 'react-router';
import { Provider } from 'react-redux';
const store = createStore(...);
const SetupView extends React.Component {
constructor (props) {
super(props);
this.handleReCaptchaChanged = () => {
// stuff
};
}
render () {
return (
<div>
{ ... }
<ReCAPTCHA
sitekey={secureKey.key}
onChange={this.handleReCaptchaChanged}
/>
</div>
);
}
}
const Layout = ({ children }) => {
// __IFRAME_CONTENT__ is replaced during the browserify build operation to match a one-line version of a HTML template, which embed custom iframe-scoped style
return (
<WidgetFrame
initialContent='__IFRAME_CONTENT__'
id='app-iframe'
>
{ ... }
{children}
</WidgetFrame>
);
};
const Router = ({ history }) => {
return (
<ConnectedRouter history={history}>
<Layout>
<Route exact path='/' component={...} />
{ ... }
<Route path='/setup' component={SetupView} />
</Layout>
</ConnectedRouter>
);
};
// `app` is the button my sdk creates and mounts into the client's webpage
ReactDOM.render(
<Provider store={store}>
<Router history={history} />
</Provider>,
app
);
I did try a few things in order to fix the recaptcha, such as copying (during runtime, after the Layout
component is mounted to the DOM) the recaptcha script tags that are generated into the main window.head
into the iframe
head, without any noticeable changes (it was a naive and desperate attempt, I'm pretty sure there's much more going on than just setting up a <script>
tag)
Do not hesitate if I can provide you with more specific informations.
Thanks for your help :)
Hi ! did you try to reproduce the issue described above ?
Hey @Manuel-Manoury I haven't had time yet. I just checked the lib you are using for iFrame. I suspect that there would need to be changes made to react-async-script.
The IFrame lib passes you the window from the context like
const MyComponent = (props, context) => {
const {
document: iframeDocument,
window: iframeWindow
} = context;
return (<...rendered jsx.../>);
};
MyComponent.contextTypes = {
window: PropTypes.any,
document: PropTypes.any
};
and so react-async-script would need to be able to use that context. Probably by having the window/document passed as a prop. And it would then use that instead of the global window/document.
I looked for solutions today too, and I came to the same conclusion. I intend to look more into react-async-script, but what feels weird is that this lib is intended for google maps and such, that would be kinda weird for it not to be useable inside an iFrame... Anyway, I'll look further into this issue and I will keep you updated :) Thanks for your help :D
@Manuel-Manoury Were you ever able to find a solution to this problem?
@jamealg I did actually, it's quite dirty but I forked this repo (sorry it's in a private organization - as I do not really have time to maintain it, at least for now) and I modified the code just a little bit to add context to the constructor, and create a this._window = context.window || window;
that is reused instead of "simply" using the window
object.
Please do note that I'm only using explicit rendering, thus I might not have all the answers to your use case.
It's a bit messy but I would advise you to :
src
to be set to the iframe hosting window.location
in order to work (but should be unspecified on chrome otherwise it would cause some encryption issue and a timeout). Well, you get the idea, we end up with an iframe (the recaptcha one) in an iframe (your custom iframe), which can be tricky to handle correctlygrecaptcha
available in the contextcomponentDidMount
lifecycle hook)These reason are also a part of why it's a private fork : I think quite poorly of this codebase, there are too many hacks and tricks involved in my opinion, but I do not have the bandwidth to tackle this for now.
Hoping it might help you, feel free to keep me updated if you happen to find a cleaner way to do this.
Cheers :)
Thank you @Manuel-Manoury I appreciate the insight. I'll definitely have to figure out that Edge issue so hopefully it's not too troublesome. I'll follow up if I come up with anything good!
Hi !
I'm trying to use your component in an
iframe
but it fails with a "cannot join the ReCaptcha service" message (without any call to theverify
callback). I guess it's an issue due to some script included / operations done at thewindow
level, without the ability to specify a custom window context (as the component works just fine if I replace theiframe
by adiv
). I think it could be interesting to add the behavior to your component to make it more versatile. If you do not think so, do you have an idea, a workaround or something to make your component work in aniframe
to help me solve my corner-case ?Thanks.