在不触发重新渲染的情况下更改 React 上下文
Change React Context without triggering a re-render
我有一个下载对话框,您可以单击它来下载我网站上的图形。因为图形是用 HTML Canvas 创建的,所以我不能简单地下载一组图像链接。我必须联系每个组件并将它们分别呈现到数据 URI 中。
在我的应用程序组件上,我定义了一个上下文来跟踪应该下载哪些组件。
export const DownloadFlagsContext = React.createContext<any>(null)
const App: React.FunctionComponent = (props) => {
const [downloadFlags, setDownloadFlags] = useState([])
return (
<DownloadFlagsContext.Provider value={{downloadFlags, setDownloadFlags}}>
<DownloadDialog/>
<div className="graphics">
<Graphic id={1}>
<Graphic id={2}>
<Graphic id={3}>
(multiple graphics)
</div>
</DownloadFlagsContext.Provider>
)
}
在我的 DownloadDialog 中,我通过将 downloadFlags 设置为需要呈现的每个组件的 ID 来触发下载。
const download = () => {
const newDownloadFlags = [] as any
for (let i = start; i < end; i++) {
newDownloadFlags.push(i)
}
setDownloadFlags(newDownloadFlags)
}
现在,在每个 Graphic 组件中,如果 downloadFlags 已更改且包含其 ID,我将触发下载。
const render = () => {
const canvas = document.createElement("canvas")
/* code to render the graphic */
return canvas.toDataURL("image/png")
}
useEffect(() => {
if (downloadFlags.includes(props.id)) {
download("filename", render())
setDownloadFlags(downloadFlags.filter((s: string) => s !== props.id))
}
}, [downloadFlags])
问题在于此代码正在触发 下载。例如,如果我将下载设置为 6 个图形,它将导致下载 21 个图像,因为每次我更改 downloadFlags 时,所有组件都将重新呈现,不同之处在于它包含的 id 少了一个。所以总共会下载 6+5+4+3+2+1 张图片。显然,如果我有很多图形要下载,这是非常糟糕的。
我想阻止组件重新渲染,以便它只下载前 6 次。
另外,我不想使用服务器。我想在客户端下载图片
我想出了解决办法。在我的应用程序组件中,我跟踪下载 ID 以及用于启用下载的布尔标志:
export const DownloadIDsContext = React.createContext<any>(null)
export const DownloadFlagContext = React.createContext<any>(null)
const App: React.FunctionComponent = (props) => {
const [downloadIDs, setDownloadIDs] = useState([])
const [downloadFlag, setDownloadFlag] = useState(false)
return (
<DownloadFlagContext.Provider value={{downloadFlag, setDownloadFlag}}>
<DownloadURLsContext.Provider value={{downloadURLs, setDownloadURLs}}>
<DownloadDialog/>
<div className="graphics">
<Graphic id={1}>
<Graphic id={2}>
<Graphic id={3}>
(multiple graphics)
</div>
</DownloadURLsContext.Provider>
</DownloadFlagContext.Provider>
)
}
在我的 DownloadDialog 中,我在开始下载时将布尔标志设置为 true。
const download = () => {
const newDownloadIDs = [] as any
for (let i = start; i < end; i++) {
newDownloadIDs.push(i)
}
setDownloadIDs(newDownloadIDs)
setDownloadFlag(true)
}
现在我不再检查子组件中的下载 ID 数组,而是只检查布尔标志。由于它立即设置为 false,它实际上只导致组件渲染一次。
useEffect(() => {
if (downloadFlag) {
if (downloadIDs.includes(props.id)) {
download("filename", render())
setDownloadIDs(downloadIDs.filter((s: string) => s !== props.id))
setDownloadFlag(false)
}
}
}, [downloadFlag])
我有一个下载对话框,您可以单击它来下载我网站上的图形。因为图形是用 HTML Canvas 创建的,所以我不能简单地下载一组图像链接。我必须联系每个组件并将它们分别呈现到数据 URI 中。
在我的应用程序组件上,我定义了一个上下文来跟踪应该下载哪些组件。
export const DownloadFlagsContext = React.createContext<any>(null)
const App: React.FunctionComponent = (props) => {
const [downloadFlags, setDownloadFlags] = useState([])
return (
<DownloadFlagsContext.Provider value={{downloadFlags, setDownloadFlags}}>
<DownloadDialog/>
<div className="graphics">
<Graphic id={1}>
<Graphic id={2}>
<Graphic id={3}>
(multiple graphics)
</div>
</DownloadFlagsContext.Provider>
)
}
在我的 DownloadDialog 中,我通过将 downloadFlags 设置为需要呈现的每个组件的 ID 来触发下载。
const download = () => {
const newDownloadFlags = [] as any
for (let i = start; i < end; i++) {
newDownloadFlags.push(i)
}
setDownloadFlags(newDownloadFlags)
}
现在,在每个 Graphic 组件中,如果 downloadFlags 已更改且包含其 ID,我将触发下载。
const render = () => {
const canvas = document.createElement("canvas")
/* code to render the graphic */
return canvas.toDataURL("image/png")
}
useEffect(() => {
if (downloadFlags.includes(props.id)) {
download("filename", render())
setDownloadFlags(downloadFlags.filter((s: string) => s !== props.id))
}
}, [downloadFlags])
问题在于此代码正在触发
我想阻止组件重新渲染,以便它只下载前 6 次。
另外,我不想使用服务器。我想在客户端下载图片
我想出了解决办法。在我的应用程序组件中,我跟踪下载 ID 以及用于启用下载的布尔标志:
export const DownloadIDsContext = React.createContext<any>(null)
export const DownloadFlagContext = React.createContext<any>(null)
const App: React.FunctionComponent = (props) => {
const [downloadIDs, setDownloadIDs] = useState([])
const [downloadFlag, setDownloadFlag] = useState(false)
return (
<DownloadFlagContext.Provider value={{downloadFlag, setDownloadFlag}}>
<DownloadURLsContext.Provider value={{downloadURLs, setDownloadURLs}}>
<DownloadDialog/>
<div className="graphics">
<Graphic id={1}>
<Graphic id={2}>
<Graphic id={3}>
(multiple graphics)
</div>
</DownloadURLsContext.Provider>
</DownloadFlagContext.Provider>
)
}
在我的 DownloadDialog 中,我在开始下载时将布尔标志设置为 true。
const download = () => {
const newDownloadIDs = [] as any
for (let i = start; i < end; i++) {
newDownloadIDs.push(i)
}
setDownloadIDs(newDownloadIDs)
setDownloadFlag(true)
}
现在我不再检查子组件中的下载 ID 数组,而是只检查布尔标志。由于它立即设置为 false,它实际上只导致组件渲染一次。
useEffect(() => {
if (downloadFlag) {
if (downloadIDs.includes(props.id)) {
download("filename", render())
setDownloadIDs(downloadIDs.filter((s: string) => s !== props.id))
setDownloadFlag(false)
}
}
}, [downloadFlag])