Надежный способ избежать ошибки «Office.js не полностью загружен» в проекте ReactJS.
Мы разрабатываем надстройки Excel. Время от времени мы это наблюдаемError: Office.js has not fully loaded. Your app must call "Office.onReady()" as part of it's loading sequence (or set the "Office.initialize" function). If your app has this functionality, try reloading this page.
Это не выглядело очень блокирующим. Однако теперь мы понимаем, что когда это происходит в Mac для Excel, область задач становится пустой страницей. Пользователям приходится перезагрузить страницу еще раз, чтобы не видеть эту ошибку и хорошо загрузить страницу.
Поэтому мы хотели бы найти надежный способ избежать этой ошибки.
Наши надстройки созданы с использованием Reactjs и dva — платформы, основанной на Redux, Redux-saga и React-Router. Вотfrontend/src/index.tsx
:
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';
import dva from 'dva';
import router from './router';
import AuthModel from './models/auth';
import SubscribtionModel from './models/subscription';
import AppModel from './models/app';
import SpreadsheetModel from './models/spreadsheet';
import UsageModel from './models/usage';
import SettingsModel from './models/settings';
import { initializeIcons } from 'office-ui-fabric-react/lib/Icons';
initializeIcons();
const app = dva();
app.model(AuthModel);
app.model(SubscribtionModel)
app.model(AppModel);
app.model(SpreadsheetModel);
app.model(UsageModel);
app.model(SettingsModel);
app.router(router);
app.start('#root');
Вотsrc/router.tsx
:
import React from 'react';
import { routerRedux, Switch, Route } from 'dva/router';
import Layout from './layouts';
import LoginPage from './components/LoginPage';
import Welcome from './components/welcome';
import SocialLoginSuccess from './components/socialLoginSuccess';
import { AwaitPromiseThenRender } from './components/AwaitPromiseThenRender';
const { ConnectedRouter } = routerRedux;
function RouterConfig({ history }: any) {
//@ts-ignore
return (
<AwaitPromiseThenRender
//@ts-ignore
promise={typeof window.__$$notInOffice !== "undefined" ? Promise.resolve(true) : Office.onReady()}
>
<ConnectedRouter history={history}>
<Layout>
<Switch>
<Route path="/sign">
<LoginPage />
</Route>
<Route path="/home">
<Welcome />
</Route>
<Route path="/app">
<App />
</Route>
... ...
... ...
</Layout>
</ConnectedRouter>
</AwaitPromiseThenRender>
);
}
export default RouterConfig;
Вотsrc/components/AwaitPromiseThenRender/index.tsx
:
import React, { Component } from 'react';
interface IProps {
promise: Promise<any>;
children: React.ReactNode;
}
interface IState {
promiseHasResolved: boolean;
}
export class AwaitPromiseThenRender extends Component<IProps> {
state: IState = { promiseHasResolved: false };
constructor(props: IProps) {
super(props);
props.promise
.then(() => this.setState({ promiseHasResolved: true }))
.catch(e => console.log("invokeGlobalErrorHandler(e)"))
}
render() {
const { children } = this.props;
const { promiseHasResolved } = this.state;
return promiseHasResolved ? children : null;
}
}
Кто-нибудь знает, как изменить наш существующий код, чтобы определенно избежатьOffice.js has not fully loaded
ошибка?
3 ответа
По сути, похоже, что ошибка сообщает вам, что существует поток, в котором вы пытаетесь что-то сделать до полной загрузки Office.js. Ваша логика кажется хорошей, но я подозреваю в коде две вещи: Я подозреваю несколько вещей:
- Возможно, проблема не на этапе рендеринга, а на этапе инициализации. Где вы вызываете app.model. Если это так, я бы попытался инициализировать onReady.
Office.onReady(()=>{
app.model(AuthModel);
app.model(SubscribtionModel)
app.model(AppModel);
app.model(SpreadsheetModel);
app.model(UsageModel);
app.model(SettingsModel);
app.router(router);
app.start('#root');
})
- Если
window.__$$notInOffice
имеет значение true/false/null, вы вообще не будете вызывать Office.onReady(). Может ли это быть проблемный поток? В таком случае просто передайте Office.onReady().
return (
<AwaitPromiseThenRender
promise={Office.onReady()}
>
Я рекомендую следовать шаблону, который использует шаблон React вашего офиса. Не визуализируйте до завершения Office.onReady(). Чтобы увидеть весь код шаблона, см. Установка генератора Yeoman — Yo Office . Запустите «yo office», а затем выберите шаблон React для создания проекта.
let isOfficeInitialized = false;
const title = "Contoso Task Pane Add-in";
const render = (Component) => {
ReactDOM.render(
<AppContainer>
<ThemeProvider>
<Component title={title} isOfficeInitialized={isOfficeInitialized} />
</ThemeProvider>
</AppContainer>,
document.getElementById("container")
);
};
/* Render application after Office initializes */
Office.onReady(() => {
isOfficeInitialized = true;
render(App);
});
Обеспечьте инициализацию Office.js. Прежде чем отображать какое-либо содержимое в надстройке, необходимо правильно инициализировать Office.js. Функция Office.onReady() предназначена для уведомления вашей надстройки, когда Office.js полностью загружен и готов к взаимодействию. Кажется, что в вашем текущем коде вы уже используете Office.onReady(), но важно убедиться, что он вызывается перед любым другим кодом, зависящим от Office.js.
Реструктуризация маршрутизации. Ваш код маршрутизации должен быть помещен в обратный вызов Office.onReady(), чтобы гарантировать, что ваше приложение не будет отображать какой-либо контент до тех пор, пока Office.js не будет готов. Это поможет предотвратить проблему с пустой областью задач. Вот как вы можете изменить свой код для достижения этой цели:
В вашем файле src/router.tsx:
Благодаря такой реструктуризации кода логика маршрутизации и рендеринга вашего приложения начнет действовать только после полной загрузки Office.js, обеспечивая плавную и безошибочную работу ваших пользователей.