这是我需要的一个外部库的特定上传功能。
我想实现的是:如果我点击我的ReactJS应用所渲染的按钮,就会打开这个外部上传对话框。
我心里有几个想法。
我先说说解决方案3。
下面是外部脚本的原始集成。
<script type="text/javascript" src="https://blabla.de/js/widget.js">
BS.CONFIG = {
"token": "546bc22e-d747-421f-b4bf-b19b5129816b",
"hostname": "https://blabla.de/match",
"redirectOnError": "ERROR_PAGE",
"postOriginalDocument": true,
"images": {
"dropbox": "https://www.blabla.de/dropbox.svg",
"googledrive": "https://www.blabla.de/googledrive.svg",
"onedrive": "https://www.blabla.de/onedrive.svg",
"cv": "https://www.blabla.de/cv.svg"
},
"postProfileUrl": "LANDING_PAGE",
"gapiClientId": "GOOGLE_API_WEBCLIENT_ID",
"oneDriveApiKey": "ONEDRIVE_APP_KEY"
}
</script>
<button id="BS_WIDGET_INITIATOR">Apply now</button>
<div id="BS_WIDGET_CONTAINER" style="display:none">
Apply with
<hr/>
<div class="BS_WIDGET" rel="dropbox"></div>
<div class="BS_WIDGET" rel="googledrive"></div>
<div class="BS_WIDGET" rel="onedrive"></div>
<hr id="BS_WIDGET_HYBRID_SEPARATOR" />
<div class="BS_WIDGET" rel="cv"></div>
</div>
<style type="text/css">
#BS_WIDGET_CONTAINER {
background-color: #fff;
box-sizing: content-box;
border: 1px solid #ccc;
border-radius: 5px;
width: 220px;
text-align: center;
color: #666;
font-family: sans-serif;
font-size: 12px;
}
.BS_WIDGET {
display: inline-block;
padding: 5px;
}
.BS_WIDGET[rel=cv],
.BS_WIDGET[rel=form] {
display: block;
text-align: left;
}
hr {
border: solid #ccc;
border-width: 1px 0 0 0;
margin: 5px 0;
}
.BS_WIDGET:hover {
background-color: #ddd;
}
.BS_WIDGET img[src$=".svg"] {
height: 32px;
width: 32px;
}
.BS_WIDGET[rel=cv] img[src$=".svg"],
.BS_WIDGET[rel=form] img[src$=".svg"] {
width: auto;
}
</style>
<script type="text/javascript" src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="DROP-INS_API_KEY"></script>
<script type="text/javascript" src="https://apis.google.com/js/client.js?onload=onGapiLoad"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load('picker', '1');
</script>
<script type="text/javascript" src="https://js.live.net/v7.0/OneDrive.js" id="onedrive-js"></script>
这是我的ReactJS方法
import { useEffect } from 'react';
const useScript = (url) => {
useEffect(() => {
const script = document.createElement('script');
script.async = true;
script.src = url;
window.BS = {
...window.BS,
CONFIG: {
token: "546bc22e-d747-421f-b4bf-b19b5129816b",
hostname: "https://blabla.de/match",
redirectOnError: "ERROR_PAGE",
postOriginalDocument: true,
images: {
dropbox: "https://www.blabla.de/dropbox.svg",
googledrive: "https://www.blabla.de/googledrive.svg",
onedrive: "https://www.blabla.de/onedrive.svg",
cv: "https://www.blabla.de/cv.svg"
},
postProfileUrl: "LANDING_PAGE",
gapiClientId: "GOOGLE_API_WEBCLIENT_ID",
oneDriveApiKey: "ONEDRIVE_APP_KEY"
}
};
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, [url]);
};
export default useScript;
import React from 'react';
import { Button } from 'antd';
import getTranslation from '../../utils/getTranslation';
import useScript from '../../utils/useScript';
const t = getTranslation;
const UploadButton = ({ uris, disabled }) => {
if (uris && uris.BS) {
useScript(uris.BS);
}
return (
<>
<div id="BS_WIDGET_CONTAINER" style={{ display: 'none' }}>
Apply with
<hr />
<div className="BS_WIDGET" rel="dropbox" />
<div className="BS_WIDGET" rel="googledrive" />
<div className="BS_WIDGET" rel="onedrive" />
<hr id="BS_WIDGET_HYBRID_SEPARATOR" />
<div className="BS_WIDGET" rel="cv" />
</div>
<Button id="BS_WIDGET_INITIATOR" disabled={disabled} type="primary">{t('upload-cv')}</Button>
</>
);
};
export default UploadButton;
但似乎BS.CONFIG没有正确设置。是我的方法不好吗?我怎么才能实现呢?
你是否使用了create-react-app,因为这甚至不应该被编译。从 文件
"React依赖于调用Hooks的顺序。 [...] 这就是为什么Hooks必须在我们组件的顶层被调用。 如果我们想有条件地运行一个效果,我们可以把这个条件放在 "Hooks "中。 里面 我们的钩子"
你需要把条件移到useEffect钩子里。
稍微说点题外话,自定义钩子最适合用于需要在各种不同组件中运行的效果,这样你就不必重复自己的工作。(也许是像表单验证这样的东西?)这个特殊的钩子的功能是将一个非常特殊的脚本附加到文档中,我怀疑你需要做不止一次。你最好把useEffect直接移到UploadButton组件中。不过这只是个人意见。
另外,React的渲染有时会略显混乱。你真的想在用户移动到卸载上传按钮的页面时删除脚本,然后在按钮被重新挂载时重新添加脚本并重新设置吗?当你在页面上有两个UploadButtons时会发生什么?脚本会被调用两次,这是一个问题吗?在原来的集成中,我想相信它在文件中只被调用一次,所以也许在useEffect钩子中对脚本进行检查,如果它已经存在,就会保释。不过,这也只是猜测,也许你的本意是这样的。
我同意第三种解决方案是最好的方法。至于脚本的执行,你应该可以把那个确切的脚本标签放在你的 index.html
.