question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Can't get hooks to work

See original GitHub issue

I implemented loadable-components using ssr but I keep getting

Uncaught 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
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
    at invariant (http://localhost:3001/static/js/client.js:132920:15)
    at resolveDispatcher (http://localhost:3001/static/js/client.js:134268:28)
    at useState (http://localhost:3001/static/js/client.js:134293:20)
    at SideMenu (http://localhost:3001/static/js/client.js:181039:151)
    at renderWithHooks (http://localhost:3001/static/js/client.js:114473:18)
    at mountIndeterminateComponent (http://localhost:3001/static/js/client.js:116555:13)

on any use of hooks. There is an Apollo query wrapping various components including those that use hooks. I originally used react-async-component. That did work but also seemed to cause similar hooks issues, although only with hot reloading and hard reloading on ssr pages with hooks. Anything that was behind an async loaded page was fine. I switched it out for @loadable in the hope of resolving the issues I had, but it’s way worse now. Any page with hooks and react-apollo now throw the above error.

Versions: react: 16.8.6 react-dom: 16.8.6 react-apollo: 2.5.5 @loadable/component: 5.9.0 @loadable/server: 5.9.0 @loadable/babel-plugin: ^5.8.0 @loadable/webpack-plugin: ^5.7.1 @material-ui: 3.9.3

I’d appreciate any help. Went through all the docs and issues but I’m completely blocked. Sorry about the long list of code.

server.js

import React from 'react';
import fs from 'fs';
import path from 'path';
import {
	renderToString,
} from 'react-dom/server';
import { Provider } from 'react-redux';
import { HelmetProvider } from 'react-helmet-async';
import { StaticRouter } from 'react-router-dom';
import { SheetsRegistry } from 'jss';
import JssProvider from 'react-jss/lib/JssProvider';
import {
	MuiThemeProvider,
	createGenerateClassName,
} from '@material-ui/core/styles';
import { ApolloProvider, getDataFromTree } from 'react-apollo';
import fetch from 'node-fetch';
import { ChunkExtractor } from '@loadable/server';
import createClient from 'common-lib/src/components/apollo';

import { get } from 'server/modules/tenant/manager';
import preload from 'modules/preload/actions';
import { theme } from 'modules/main/components/Theme';
import configureStore from 'store/configureStore';
import App from 'App';
import clientVars from 'server/config/clientVars';
import ServerHTML from './ServerHTML';

const appDirectory = fs.realpathSync(process.cwd());
const webStatsFile = path.resolve(
	appDirectory,
	'build/loadable-stats-web.json',
);

const graphQLURL = process.env.RAZZLE_RUNTIME_GRAPHQL_URL;
const wsURL = process.env.RAZZLE_RUNTIME_GRAPHQL_WS;

const reactApplicationMiddleware = async (req, res) => {
	try {
		const client = createClient(true, { req, fetch });

		const store = configureStore();

		const sheetsRegistry = new SheetsRegistry();
		const sheetsManager = new Map();
		const generateClassName = createGenerateClassName();

		const extractor = new ChunkExtractor({
			statsFile: webStatsFile,
			entrypoints: ['client'],
		});

		const reactRouterContext = {};
		const helmetContext = {};

		const TheApp = () => (
			<ApolloProvider client={client}>
				<Provider store={store}>
					<JssProvider
						registry={sheetsRegistry}
						generateClassName={generateClassName}
					>
						<MuiThemeProvider
							theme={theme}
							sheetsManager={sheetsManager}
						>
							<HelmetProvider context={helmetContext}>
								<StaticRouter
									location={req.url}
									context={reactRouterContext}
								>
									<App />
								</StaticRouter>
							</HelmetProvider>
						</MuiThemeProvider>
					</JssProvider>
				</Provider>
			</ApolloProvider>
		);
		if (reactRouterContext.status) {
			res.status(reactRouterContext.status);
		}
		if (reactRouterContext.url) {
			res.redirect(
				reactRouterContext.status === 301 ? 301 : 302,
				reactRouterContext.url,
			);
			return;
		}
		const { params } = req;

		const site = await get();

		await preload(
			store,
			clientVars,
			site,
			params,
		);

		const preloadedState = store.getState();
		const jsx = extractor.collectChunks(
			<TheApp configVars={clientVars} preloadedState={preloadedState} />,
		);
		try {
			await getDataFromTree(jsx);
		} catch (err) {
			console.error('Error while running `getDataFromTree`', err);
		}
		const initialApolloState = client.extract();

		const html = renderToString(
			<ServerHTML
				helmet={helmetContext.helmet}
				css={sheetsRegistry.toString()}
				state={initialApolloState}
				graphQLURL={graphQLURL}
				preloadedState={preloadedState}
				wsURL={wsURL}
				extractor={extractor}
			>
				{jsx}
			</ServerHTML>,
		);

		switch (reactRouterContext.status) {
			case 301:
			case 302:
				res.status(reactRouterContext.status);
				res.location(reactRouterContext.url);
				res.end();
				break;
			case 404:
				res.status(reactRouterContext.status);
				res.type('html');
				res.write('<!doctype html>');
				res.write(html);
				res.end();
				break;
			default:
				res.status(200);
				res.type('html');
				res.write('<!doctype html>');
				res.write(html);
				res.end();
		}
	} catch (err) {
		console.log(err);
		res.status(500).send(`Something went wrong: ${err.message}`);
	}
};

export default reactApplicationMiddleware;

client.js

import React from 'react';
import { hydrate } from 'react-dom';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { ApolloProvider } from 'react-apollo';
import { HelmetProvider } from 'react-helmet-async';
import JssProvider from 'react-jss/lib/JssProvider';
import createGenerateClassName from '@material-ui/core/styles/createGenerateClassName';
import { loadableReady } from '@loadable/component';

import Theme from 'modules/main/components/Theme';
import createClient from 'common-lib/src/components/apollo';
import configureStore from 'store/configureStore';

import clientVars from 'server/config/clientVars';
import App from './App';

const supportsHistory = 'pushState' in window.history;

const client = createClient();

const preloadedState = window.__PRELOADED_STATE__;

if (process.env.NODE_ENV !== 'production') {
	delete window.__PRELOADED_STATE__;
}

export const store = configureStore(preloadedState);
const generateClassName = createGenerateClassName();

loadableReady(() => {
	const app = (
		<ApolloProvider client={client}>
			<Provider store={store}>
				<JssProvider generateClassName={generateClassName}>
					<Theme>
						<BrowserRouter forceRefresh={!supportsHistory}>
							<HelmetProvider>
								<App configVars={clientVars} />
							</HelmetProvider>
						</BrowserRouter>
					</Theme>
				</JssProvider>
			</Provider>
		</ApolloProvider>
	);

	hydrate(app, document.querySelector('#root'));
});

if (module.hot) {
	module.hot.accept();
}

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:8 (2 by maintainers)

github_iconTop GitHub Comments

9reactions
mbrochhcommented, Jun 26, 2019

I’m having the same issue. With a Razzle app, as soon as I add loadable-components to the mix, I can’t use hooks any more, same error as OP.

UPDATE:

I found it. Unlikely to be related to OPs problem, as my case is Razzle specific.

A new Razzle app has this in server.js:

${
  process.env.NODE_ENV === 'production'
    ? `<script src="${assets.client.js}" defer></script>`
    : `<script src="${assets.client.js}" defer crossorigin></script>`
}

That needs to be removed! Because when one follows the loadable-components docs, one will add something like this:

const scriptTags = extractor.getScriptTags()

And that scriptTags variable contains all chunks AND the main bundle.js - so just like the error message suggested, I was indeed loading React twice because I was loading two bundle.js files.

Took me three hours to figure this out…

1reaction
jlramosrcommented, Nov 13, 2020

I’m having the same issue. With a Razzle app, as soon as I add loadable-components to the mix, I can’t use hooks any more, same error as OP.

UPDATE:

I found it. Unlikely to be related to OPs problem, as my case is Razzle specific.

A new Razzle app has this in server.js:

${
  process.env.NODE_ENV === 'production'
    ? `<script src="${assets.client.js}" defer></script>`
    : `<script src="${assets.client.js}" defer crossorigin></script>`
}

That needs to be removed! Because when one follows the loadable-components docs, one will add something like this:

const scriptTags = extractor.getScriptTags()

And that scriptTags variable contains all chunks AND the main bundle.js - so just like the error message suggested, I was indeed loading React twice because I was loading two bundle.js files.

Took me three hours to figure this out…

Thanks man, hours and hours of research until I saw this

Read more comments on GitHub >

github_iconTop Results From Across the Web

I can't get my hooks to work in React Native, what am i doing ...
So the issue i'm having is that my hook to update the values arent updating the values. The hook that updates the geolocation,...
Read more >
Rules of Hooks - React
Don't call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any...
Read more >
Understanding common frustrations with React Hooks
React Hooks can be frustrating despite their popularity and widespread use. Learn about some of the drawbacks to using React Hooks.
Read more >
Can't get hooks to run after profile updates - WordPress.org
I am trying to do an action after a profile update happens. I've tried um_after_user_updated, um_user_edit_profile, um_user_after_updating_profile.
Read more >
How To Get Command Hooks To Stick Just About Anywhere
Check out these tips & tricks that will help you master the use of any Command ... How To Get Command Hooks To...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found