首页 > 解决方案 > 如何在不更新状态的情况下显示模态

问题描述

我整整一个工作日都在旋转我的齿轮,试图弄清楚如何做到这一点。我有一个呈现 PowerBi 嵌入式报表的组件。我在页面上有一个按钮,需要弹出一个 Bootstrap Modal 包装的组件。我可以通过状态正常执行此操作,但由于嵌入了 PowerBi 报告,我无法更改状态(因为这将重新呈现 PowerBI 报告,这需要时间,并且还会重置报告)。我曾尝试使用 useRef() 来存储此变量,但显然它不会通知 Modal 组件的更改。

想法?有什么建议吗?

import React, {useEffect, useRef, useState,useMemo} from 'react';
import ReportManager from '../managers/reportManager';
import SubscribeModel from '../components/subscription/SubscribeModal';
// @ts-ignore
import Report from 'powerbi-report-component';
import {FaChartLine, FaChartBar, FaDesktop, FaPrint, FaMailBulk} from 'react-icons/fa';
import PreloadManager from '../managers/preloadManager';
// @ts-ignore
import LoadingOverlay from 'react-loading-overlay';
import Preloader from '../components/Preloader';

interface ReportConfig {
    id : string;
    name : string;
    webUrl : string;
    embedUrl : string; //Embed URL
    datasetId : string; //Report ID
    embedToken : string; //Embed Token
}

class ReportConfigReal implements ReportConfig {
    'id' : string;
    'name' : string;
    'webUrl' : string;
    'embedUrl' : string;
    'datasetId' : string;
    'embedToken' : string;
    'expiration' : string;
}

const Reports = (props : any) => {
    const [config,
        setConfig] = useState({
        id: "",
        name: "",
        webUrl: "",
        embedUrl: "",
        embedToken: "",
        expiration: ""
    });
    const [currentUser,
        setCurrentUser] = useState(props.currentuser);
    const [reportList,
        setReportList] = useState(new Array());
    const [reportId,
        setReportId] = useState(props.match.params.report_id);
    const [loading,
        setLoading] = useState(false);
    const [reportsLoading,
        setReportsLoading] = useState(false);
    const [report,
        setReport] = useState(null);
    const [subModal,
          setSubModal] = useState(false);        

    let reportManager : ReportManager = new ReportManager();
    let preloadManager : PreloadManager = new PreloadManager();

    const currentPage = useRef(null);
    const showSubscribe = useRef(null);

    const createExpiration = (minutes : number) => {
        const date = new Date();
        return new Date(date.getTime() + minutes * 60000);
    };

    const onLoadAndSetTokenListener = (reportFromCallback : any) => {
        setTokenExpirationListener(config.expiration, 1);
        setReport(reportFromCallback);
    };

    const setTokenExpirationListener = (tokenExpiration : string, minutesToRefresh = 2) => {
        // time until token refresh in milliseconds
        const currentTime = Date.now();
        const expiration = Date.parse(tokenExpiration);
        const safetyInterval = minutesToRefresh * 60 * 1000;

        let timeout = expiration - currentTime - safetyInterval;
        // if token already expired, generate new token and set the access token
        if (timeout <= 0) {
            console.log('Updating Report Embed Token');
            updateToken() // set timeout so minutesToRefresh minutes before token expires, token will be
            // updated;
        } else {
            console.log('Report Embed Token will be updated in ' + timeout + ' milliseconds.');
            setTimeout(() => {
                console.log('Set time out');
                updateToken();
            }, timeout);
        }
    };

    const updateToken = () => {
        console.log('Update token called');
        // Generate new EmbedToken (Axios call to get config/ token)
        reportManager
            .generateEmbedToken(currentUser)
            .then((res : any) => {
                // Set AccessToken (Use the report object)
                if (report !== null) {
                    report
                        .setAccessToken(res.embedToken)
                        .then(() => {
                            console.log('new token set');
                            setTokenExpirationListener(createExpiration(2).toString(), 1);
                        })
                        .catch((err : any) => console.error('Error setting token', err));
                }
            });
    };
    const handleFullScreen = () => {
        var elem = document.documentElement;
        elem.requestFullscreen();
    };
    const handlePrint = () => {
        window.print();
    };

     const handleSubscribe = () => {
        console.log("page", currentPage.current);
        console.log("showsub", showSubscribe);

    };
    const handleReportChange = (e : any) => {
        window.location.href = '/reports/' + e;
    };

    const handleDataSelected = (data : any) => {
        console.log("data selected", data);
    };

    const handlePageChange = (data : any) => {
        console.log("page changed", data);
        currentPage.current = data.newPage;
    };

    useEffect(() => {
        let promiseList : any = [];
        setLoading(true);
        setReportsLoading(true);
        if (currentUser && currentUser.allowedReports.length !== 0) {
            currentUser
                .allowedReports
                .forEach((report : string) => {
                    promiseList.push(reportManager.getReportInfo(currentUser, report).then((info : any) => {
                        return info;
                    }),);
                });
        }

        Promise
            .all(promiseList)
            .then(values => {
                setReportList(values);
            });

        if (currentUser && currentUser.allowedReports.length !== 0 && currentUser.authenticated) {
            if (reportId === undefined) {
                reportManager
                    .getReport(currentUser)
                    .then(data => {
                        setConfig(data);
                        setLoading(false);
                        setReportsLoading(false);
                    })
                    .catch(error => {
                        console.log(error);
                    });
            } else {
                reportManager
                    .getReportInfo(currentUser, reportId)
                    .then((info : any) => {
                        setConfig(info);
                        setLoading(false);
                        setReportsLoading(false);
                    });
            }
        }
    }, []);

    return (
        <LoadingOverlay active={loading} spinner={< Preloader />}>
            <div>
                <div
                    className={reportsLoading !== true
                    ? 'slide-wrapper'
                    : 'col-sm-12 loading-delete'}>
                    <div id="slide-report">
                        <div className="menu_icon">
                            <div>
                                <FaChartLine color="#003267" size="30"/>
                            </div>
                            <span>Reports</span>
                        </div>
                        <div className="menu_content">
                            <ul>
                                {reportList.map((report, index) => {
                                    return (
                                        <li key={index} onClick={() => handleReportChange(report.id)}>
                                            <FaChartBar className="icon-slide" color="#fff" size="30"/>
                                            <span>{report
                                                    .name
                                                    .slice(0, 25)}</span>
                                        </li>
                                    );
                                })}
                            </ul>
                        </div>
                    </div>
                    <div id="slide-full-screen">
                        <div className="menu_icon" onClick={handleFullScreen}>
                            <div>
                                <FaDesktop color="#003267" size="30"/>
                            </div>
                            <span>Full Screen</span>
                        </div>
                    </div>
                    <div id="slide-print">
                        <div className="menu_icon" onClick={handlePrint}>
                            <div>
                                <FaPrint color="#003267" size="30"/>
                            </div>
                            <span>Print</span>
                        </div>
                    </div>
                    <div id="slide-subscribe">
                        <div className="menu_icon" onClick={handleSubscribe}>
                            <div>
                                <FaMailBulk color="#003267" size="30"/>
                            </div>
                            <span>Subscribe</span>
                        </div>
                    </div>
                </div>
                <div
                    key={reportId}
                    className={loading !== true
                    ? 'col-sm-12'
                    : 'col-sm-12 loading-delete'}>
                    <Report
                        className={reportId}
                        embedType="report"
                        tokenType="Embed"
                        pageName={reportId}
                        accessToken={config.embedToken}
                        embedUrl={config.embedUrl}
                        embedId={config.id}
                        permissions="All"
                        reportMode="view"
                        onLoad={onLoadAndSetTokenListener}
                        onPageChange={handlePageChange}
                        onSelectData={handleDataSelected}
                        style={{
                        height: '90vh',
                        width: '100%',
                        display: 'block',
                        top: '0',
                        left: '0',
                        position: 'absolute',
                        border: '0',
                        padding: '20px',
                        background: '#fff',
                        zIndex: '1'
                    }}/>
                </div>
            </div>
            <SubscribeModel show={false} />
        </LoadingOverlay>
    );
};

export default Reports;

标签: reactjs

解决方案


这看起来是错误的做法,但这将打开一个模式而无需更新状态。您是否考虑过查看componentShouldUpdate?powerBiReport 也不应该重新渲染,除非传递给它的任何道具已经改变或报告本身的状态已经改变,所以考虑看看那里。

/* -- snip -- */
onButtonClick={() => createModal(<YourModal onClose={removeModal}/>)}
/* -- snip -- */

const createModal(component) {
  const container = document.appendChild("div");
  container.id = "modal-container";
  ReactDOM.render(container, component);
}

const removeModal() {
  const container = document.getElementById("modal-container");
  ReactDOM.unmountComponentAtNode(container);
}

推荐阅读