javascript - React/Node 应用程序无法在 Chrome 上运行“错误运行模板:不变违规:无效的挂钩调用”
问题描述
我的 react/node/meteor 应用程序出现错误。特别是,该应用无法在 Chrome 上加载,但在所有其他浏览器(edge、firefox)上都能正常运行。在 Chrome 上,我收到 500 错误并且页面无法加载。在我运行应用程序的终端上,我得到了这个:
(webapp_server.js:1010) Error running template: Invariant Violation: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks...
我知道这个错误有三个常见的原因,正如我们在这里看到的:
https://reactjs.org/warnings/invalid-hook-call-warning.html
但我使用的是“react”:“^16.8.0”,“react-dom”:“^16.8.0”,我不使用 react native。
我不相信我不正确地使用了钩子。
我跑了这个:meteor npm ls react
并得到以下回复:`-- react@16.8.6
我已经重置了我的机器,但问题仍然存在:Edge 工作正常,Chrome 无法加载。
这是出现错误的代码:
import React from 'react';
import MeteorLoadable from 'meteor/nemms:meteor-react-loadable';
import acceptLanguage from 'accept-language';
import { renderToString } from 'react-dom/server';
import { ServerStyleSheet } from 'styled-components';
import { Meteor } from 'meteor/meteor';
import { onPageLoad } from 'meteor/server-render';
import { ApolloClient } from 'apollo-client';
import { ApolloProvider, getDataFromTree } from 'react-apollo';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
import { StaticRouter, Route } from 'react-router-dom';
import Helmet from 'react-helmet';
import fetch from 'node-fetch';
import App from '/app/ui/components/smart/app';
import HeaderTitle from '/app/ui/components/smart/header/header-title';
import LanguagePicker from '/app/ui/components/dumb/language-picker';
import Routes from '/app/ui/routes';
import { primaryLocale, otherLocales } from '/app/intl';
const locales = primaryLocale ? [primaryLocale, ...otherLocales] : otherLocales;
acceptLanguage.languages(locales);
const render = async (sink) => {
const ssrClient = new ApolloClient({
link: new HttpLink({
uri: Meteor.absoluteUrl('/graphql'),
fetch,
}),
cache: new InMemoryCache(),
ssrMode: true,
});
const preferredLocale = acceptLanguage.get(sink.request.headers['accept-language']);
let locale = otherLocales.find(l => sink.request.url.path.startsWith(`/${l}`));
let prefix = locale;
// /app-shell is a special route that does no server-side rendering
// It's used by the service worker for all navigation routes, so after the first visit
// the initial server response is very quick to display the app shell, and the client
// adds in the data.
// In the case of a first visit or a robot, we render everything on the server.
if (sink.request.url.path === '/app-shell') {
sink.appendToBody(`<script>window.__APOLLO_STATE__=${JSON.stringify(ssrClient.extract())};</script>`);
sink.appendToBody(`<script>window.__PREFERRED_LOCALE__='${preferredLocale}';</script>`);
sink.appendToBody(MeteorLoadable.getLoadedModulesScriptTag());
return;
}
// We first check if we need to redirect to a locale
// We can only do this is there isn't a primary locale.
if (!primaryLocale) {
if (!locale) {
sink.setStatusCode(307);
sink.redirect(`/${preferredLocale || otherLocales[0]}${sink.request.url.path}`);
return;
}
} else if (!locale) {
// If there's no locale prefix, we use the primaryLocale instead
locale = primaryLocale;
prefix = '';
}
const ServerApp = ({ component, context }) => (
<MeteorLoadable.Capture>
<StaticRouter location={sink.request.url} context={context}>
<ApolloProvider client={ssrClient}>
<Route
path={`/${prefix}`}
render={props => <App component={component} {...props} locale={locale} section="app" />}
/>
</ApolloProvider>
</StaticRouter>
</MeteorLoadable.Capture>
);
// Load all data from local server
const context = {};
await getDataFromTree(<ServerApp component={Routes} context={context} />);
// Elements that we want rendered on the server
const sheet = new ServerStyleSheet();
sink.renderIntoElementById('header-title', renderToString(sheet.collectStyles(<ServerApp component={HeaderTitle} context={context} />)));
sink.renderIntoElementById('header-lang-picker', renderToString(sheet.collectStyles(<ServerApp component={LanguagePicker} context={context} />)));
sink.renderIntoElementById('main', renderToString(sheet.collectStyles(<ServerApp component={Routes} context={context} />)));
// Append helmet and styles
const helmetResult = Helmet.renderStatic();
['title', 'meta', 'link', 'script'].forEach(k => sink.appendToHead(helmetResult[k].toString()));
sink.appendToHead(sheet.getStyleTags());
// Append user's preferred locale
sink.appendToBody(`<script>window.__PREFERRED_LOCALE__='${preferredLocale}';</script>`);
// Append Apollo data
sink.appendToBody(`<script>window.__APOLLO_STATE__=${JSON.stringify(ssrClient.extract())};</script>`);
// Append preloaded ReactLoadabe modules
sink.appendToBody(MeteorLoadable.getLoadedModulesScriptTag());
};
Meteor.startup(async () => {
await MeteorLoadable.preloadComponents();
onPageLoad(render);
});
特别是返回错误的是这一行:
await getDataFromTree(<ServerApp component={Routes} context={context} />);
我评论了这条线,该应用程序现在似乎运行良好。我不知道我是否需要它,它不应该引起问题。此代码是从入门工具包中逐行复制的,我不知道此代码在做什么。
注意:此代码取自以下入门工具包:
https://github.com/timothyarmes/ta-meteor-apollo-starter-kit
解决方案
看起来这确实违反了钩子,所以我更改了以下代码:
await getDataFromTree(<ServerApp component={Routes} context={context} />);
对此:
const aServerApp = () => (
<ServerApp component={Routes} context={context} />
);
await getDataFromTree(aServerApp);
它似乎工作正常。
推荐阅读
- selectize.js - 选择自定义选项视图
- javascript - 将嵌套对象的每个对象的索引设置为属性
- ios - 从 iphone swift xcode 与 HM10 通信
- c# - 如何在 C# 中设置版本名称?
- php - Jquery AJAX 调用不起作用并且总是进入错误函数
- node.js - 具有锐利调整大小图像的 multer(上传前 - 使用 toBuffer)
- docker - HAProxy boshrelease + Docker boshrelease 链接
- sql-server-2008 - 在 SQL Server 中拆分单词
- scala - 减少我在 scala 中处理的行数
- api - 在超级账本作曲家中创建资产资产