简体   繁体   English

如何通过 react-share 共享动态生成的图像?

[英]How to share a dynamically generated image from react with react-share?

I have a react app which generates images on the front end dynamically using Plotly.js .我有一个反应应用程序,它使用Plotly.js在前端动态生成图像。 I'd like to add image sharing functionality.我想添加图像共享功能。 I am trying to use react-share for this.我正在尝试为此使用react-share Social platforms require image URL for image sharing and do not support images in base64 encoding or alike.社交平台需要图片 URL 进行图片分享,不支持 base64 等编码的图片。 Backend was implemented so it can receive images in base64, store in the database and return URL to the image, which is then used for sharing with react-share .实现了后端,因此它可以接收 base64 中的图像,存储在数据库中并返回 URL 到图像,然后用于与react-share

As the image is generated dynamically (it changes each time user resizes the chart, for instance), everything should be done when user clicks on Share icon.由于图像是动态生成的(例如,每次用户调整图表大小时它都会更改),当用户单击“共享”图标时,一切都应该完成。

So after the user has clicked on the Share icon, the image generated on the front end should be saved to back end所以用户点击分享图标后,前端生成的图片应该保存到后端

let imgURI;

  const handleClick = () => {
    Plotly.toImage('chartContainer', {
      format: 'png',
      width: 1000,
      height: 600
    })
      .then(dataUrl => api.post('/image/base64ToPng', { image: dataUrl })
        .then(
          (response) => {
            imgURI = response.data.imgURI;
          },
          failure => console.error(failure)
        ));
  };

after the response is received, passed down to the sharing component like this收到响应后,像这样传递给共享组件

<FacebookShareButton
            url={imgURI}
          >
     <FacebookIcon/>
</FacebookShareButton>

The code sample is not asynchronous, so the image URI is not passed to the sharing component, therefore sharing does not work.代码示例不是异步的,因此图像 URI 未传递到共享组件,因此共享不起作用。 I tried to pass the prop down using conditional depending on whether it's defined or not and did not come up with a solution.我试图根据是否定义使用条件传递道具,但没有提出解决方案。 I also looked up some issues in react-share repo that dealt with async urls, but seems like none of them deals with the dynamic image sharing on click.我还在react-share repo中查找了一些处理异步 url 的问题,但似乎没有一个处理单击时的动态图像共享。

I'd very appreciate a hint on how to complete this task.我非常感谢有关如何完成此任务的提示。

This is serious hack territory, and the whole thing would be a lot simpler if this PR had been completed.这是一个严重的黑客领域,如果这个 PR已经完成,整个事情就会简单得多。

However, the code below should work (see codesandbox ).但是,下面的代码应该可以工作(参见代码和)。

The key steps are:关键步骤是:

  1. Have a bit of state that keeps track of whether you have a url from the service or not.有一些状态来跟踪您是否有来自服务的 url。
  2. When this state is "none", disable the facebook button's default behavior (ie openShareDialogOnClick = false )当此状态为“无”时,禁用 facebook 按钮的默认行为(即openShareDialogOnClick = false
  3. Add an onClick handler to the facebook button that asynchronously fetches the url and sets the state (triggering a re-render)向 facebook 按钮添加一个onClick处理程序,该处理程序异步获取 url 并设置状态(触发重新渲染)
  4. Use an effect + ref so that when the url is set to something real, you manually call the click event on the button (which now has a real address in its url prop), and then re-sets the url to "none"使用 effect + ref 以便当 url 设置为真实的东西时,您手动调用按钮上的点击事件(现在它的url属性中有一个真实的地址),然后将 url 重新设置为“无”
import { useEffect, useRef, useState } from "react";
import { FacebookIcon, FacebookShareButton } from "react-share";

async function getUrFromService(): Promise<string> {
  // The real implementation would make a network call here.
  await new Promise((resolve) => setTimeout(resolve, 1000));
  return "https://via.placeholder.com/150";
}

export default function App() {
  const shareButton = useRef<HTMLButtonElement>(null);
  const [url, setUrl] = useState<string>("none"); // Unfortunately, we have to have a dummy string here, or FacebookShareButton will blow up.

  // Provide an onClick handler that asyncronously fetches the url and sets it in the state.
  const onClick = async () => {
    // Be sure to check for the "none" state, so we don't trigger an infinite loop.
    if (url === "none") {
      const newUrl = await getUrFromService();
      setUrl(newUrl);
    }
  };

  // Whenever "url" changes and we re-render, we manually fire the click event on the button, and then re-set the url.
  useEffect(() => {
    if (url !== "none") {
      shareButton.current?.click();
      setUrl("none");
    }
  }, [url, shareButton]);

  return (
    <FacebookShareButton
      ref={shareButton}
      // Disable calling the dialog if we don't have a url yet.
      openShareDialogOnClick={url !== "none"}
      url={url}
      onClick={onClick}
    >
      <FacebookIcon />
    </FacebookShareButton>
  );
}

Use navigator.share api if possible.如果可能,请使用navigator.share api。

Having, said that you could write a wrapper that manages loading state and disables icon of component.话虽如此,您可以编写一个包装器来管理加载状态并禁用组件的图标。

Create a async share component创建异步共享组件

//AsyncShareLoader.jsx
const AsyncShareLoader = ({ url, children }) => {
  const loading = !url;
  return (
    <div style={{ filter: `grayscale(${loading ? "100%" : "0%"}` }}>
      {React.Children.map(children, (child) =>
        React.cloneElement(child, {
          disabled: loading,
          url: loading ? "none" : url,
          openShareDialogOnClick: !loading
        })
      )}
    </div>
  );
};

Now, use this as a wrapper for your actual react-share icons.现在,将其用作实际 react-share 图标的包装器。 Something like this像这样的东西

const Share = () => {
  const [url, setUrl] = useState()

  useEffect(() => {
    fetch('/imgUrl').then(getUrlFromRes).then(setUrl)
  }, [])

  return (
    <AsyncShareLoader url={url}>
      <FacebookShareButton>
        <FacebookIcon />
      </FacebookShareButton>
    </AsyncShareLoader>    
  );
}

Extending this techinique you could manually steal click as Andrew suggested扩展这项技术,您可以按照安德鲁的建议手动窃取点击

const getBase64ImageFromUrl = url => fetch(url).then(response => response.blob()).then( blob => new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.onerror = reject; blob = new Blob([blob], {type: 'image/png'}); reader.readAsDataURL(blob); }), ); const getBase64ImageFromUrl = url => fetch(url).then(response => response.blob()).then( blob => new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.onerror = reject; blob = new Blob([blob], {type: 'image/png'}); reader.readAsDataURL(blob); }), );

const shareData = async () => { const shareData = async () => {

await getBase64ImageFromUrl('https://url of image').then(base64 => {
  const shareOption = {
    title: App Link,
    url: base64,
    message:
      'Download app now: ,AppLink:""',
  };
  try {
    const shareResponse = Share.open(shareOption);
    console.log('share response ,', shareResponse);
  } catch (error) {
     alert(error.message);
  }
});

}; };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM