Where is the correct place to call injectTapEventPlugin() in a next.js based application?
Hey @nic,
I am also interested in this answer. But personally I don't think a next.js application is any different from other React apps.
Personally what I've done is to inject it in the main layout of my app, when component is mounted. Here is the code:
import Head from 'next/head';
import injectTapEventPlugin from 'react-tap-event-plugin';
import React from 'React';
class MainLayout extends React.Component {
componentDidMount() {
injectTapEventPlugin();
}
render() {
const { children } = this.props;
return (
<div>
<Head>
<title>My page title</title>
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
{children}
</div>
)
}
}
export default MainLayout;
Happy to hear any feedbacks!
@nic Just for your info, there are some issues with Material-UI and other toolkits: #119, #196, #204, #221.
@QuentinDejean Thanks a lot for your interested. I try the follow code:
import React from 'react';
import Head from 'next/head';
import injectTapEventPlugin from 'react-tap-event-plugin';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import AppBar from 'material-ui/AppBar';
const muiTheme = getMuiTheme({ userAgent: false });
export default class extends React.Component {
componentDidMount() {
injectTapEventPlugin();
}
render() {
return (
<MuiThemeProvider muiTheme={muiTheme}>
<div>
<Head>
<title>My page title</title>
<meta name="viewport" content="initial-scale=1.0, width=device-width"/>
</Head>
<AppBar
title="Title"
iconClassNameRight="muidocs-icon-navigation-expand-more"
/>
<h1>Page content</h1>
</div>
</MuiThemeProvider>
)
}
}
And the result is:
After click into the Icon Navigation I get more warnings:
I try to change _componentDidMount_ to _componentWillMount_ but the result is:
{ Error: Invariant Violation: injectTapEventPlugin(): Can only be called once per application lifecycle.
It is recommended to call injectTapEventPlugin() just before you call ReactDOM.render(). If you are using an external library which calls injectTapEventPlugin() itself, please contact the maintainer as it shouldn't be called in library code and should be injected by the application.
at invariant (/Volumes/Projects/node_modules/react-tap-event-plugin/node_modules/fbjs/lib/invariant.js:39:15)
at injectTapEventPlugin (/Volumes/Projects/node_modules/react-tap-event-plugin/src/injectTapEventPlugin.js:11:5)
at _class.componentWillMount (/Volumes/Projects/.next/dist/pages/index.js:66:41)
at /usr/local/lib/node_modules/next/node_modules/react/lib/ReactCompositeComponent.js:347:23
at measureLifeCyclePerf (/usr/local/lib/node_modules/next/node_modules/react/lib/ReactCompositeComponent.js:74:12)
at ReactCompositeComponentWrapper.performInitialMount (/usr/local/lib/node_modules/next/node_modules/react/lib/ReactCompositeComponent.js:346:9)
at ReactCompositeComponentWrapper.mountComponent (/usr/local/lib/node_modules/next/node_modules/react/lib/ReactCompositeComponent.js:257:21)
at Object.mountComponent (/usr/local/lib/node_modules/next/node_modules/react/lib/ReactReconciler.js:47:35)
at ReactCompositeComponentWrapper.performInitialMount (/usr/local/lib/node_modules/next/node_modules/react/lib/ReactCompositeComponent.js:370:34)
at ReactCompositeComponentWrapper.mountComponent (/usr/local/lib/node_modules/next/node_modules/react/lib/ReactCompositeComponent.js:257:21) framesToPop: 1 }
:(
After click into the Icon Navigation I get more warnings...
@nic This is exactly what #204 and #221 are about. Material-UI is using react-addons-transition-group, which inlines React into your bundle, so you end up with two Reacts on the same page (one from Next bundle, and one from yours). Try to follow the #221 and see if that will help you with Material-UI as it helped me with React-MD.
@frol Oh!! Now I got it. Thank you so much!! Your PR is very appreciated. I'll try that. You rock Vlad! :)
Still not quite getting it, similar to above I have a button that turns black and spews errors after clicking. I see the PR but am not sure how to translate for Material UI rather than React-MD? I keep trying but so far no luck.
Same problem here, there's any solution for this?
2.0 is coming and it has all the fixes for these and you will be able to use them like as you are doing with other React apps.
@arunoda I'm testing with the 2.0 beta and still can't make it work, I can't find the right place to put injectTapEventPlugin()
. Tried with different options and still seeing this error:
Invariant Violation: injectTapEventPlugin(): Can only be called once per application lifecycle.
It is recommended to call injectTapEventPlugin() just before you call ReactDOM.render(). If you are using an external library which calls injectTapEventPlugin() itself, please contact the maintainer as it shouldn't be called in library code and should be injected by the application.
at invariant (/Users/mauro/Workspace/foodvana/foodvana-enduser-web-next/node_modules/fbjs/lib/invariant.js:38:15)
at injectTapEventPlugin (/Users/mauro/Workspace/foodvana/foodvana-enduser-web-next/node_modules/react-tap-event-plugin/src/injectTapEventPlugin.js:11:5)
at Function.getInitialProps (/Users/mauro/Workspace/foodvana/foodvana-enduser-web-next/pages/index.js?entry:24:6)
at _callee3$ (/Users/mauro/Workspace/foodvana/foodvana-enduser-web-next/next/dist/server/render.js:120:81)
at tryCatch (/Users/mauro/Workspace/foodvana/foodvana-enduser-web-next/next/node_modules/regenerator-runtime/runtime.js:64:40)
at GeneratorFunctionPrototype.invoke [as _invoke] (/Users/mauro/Workspace/foodvana/foodvana-enduser-web-next/next/node_modules/regenerator-runtime/runtime.js:355:22)
at GeneratorFunctionPrototype.prototype.(anonymous function) [as next] (/Users/mauro/Workspace/foodvana/foodvana-enduser-web-next/next/node_modules/regenerator-runtime/runtime.js:116:21)
at step (/Users/mauro/Workspace/foodvana/foodvana-enduser-web-next/next/node_modules/babel-runtime/helpers/asyncToGenerator.js:17:30)
at /Users/mauro/Workspace/foodvana/foodvana-enduser-web-next/next/node_modules/babel-runtime/helpers/asyncToGenerator.js:28:13
Any idea how to make it work?
Also, great work, 2.0 looks great!
Read error messages :)
Invariant Violation: injectTapEventPlugin(): Can only be called once per application lifecycle.
Just do this in the top of your file:
import injectTapEventPlugin from 'react-tap-event-plugin'
injectTapEventPlugin()
Thanks a lot for your response @arunoda, really appreciated!
Already tried that and in the first render it works perfectly, but after a hot reload or a transition with a Link, it fails again.
I tried putting it in the top of every Page, also in a parent component I re-use in all pages. But keep failing.
Send me a sample repo. Let's see what we can about this.
@arunoda here I created one nextjs2-materialui-sample
Thanks for your help!
@EehMauro there's a simple fix for this.
Add following content to a file in components/tap_events.js
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();
Then import it inside each of your pages like this:
import '../components/tap_events'
Thanks @arunoda, now it's working perfectly!
Great.
It's not working, after hot reload it fails over and over again.
Tried @arunoda solution but still the same error
EDIT
It does work, you just have to restart the server
@jsantana90 Quick fix (Runs injectTapEventPlugin only on the client side):
if (typeof window !== 'undefined') injectTapEventPlugin();
@jsantana90 you can also create a custom document and import the module inside that.
See: https://github.com/zeit/next.js#custom-document
@arunoda I tried that:
https://github.com/GraphQLGuide/guide/blob/repro-tap-plugin/pages/_document.js#L4-L7
On first pageload I get:
and no error in the terminal. After saving a file, I get:
Invariant Violation: injectTapEventPlugin(): Can only be called once per application lifecycle
in the terminal. Guarding it with if (typeof window !== 'undefined')
also doesn't work.
Repro:
npm run dev
https://github.com/GraphQLGuide/guide/tree/repro-tap-plugin
@ooade your solution works for me, btw, you can wrap in try catch like this:
try {
injectTapEventPlugin();
} catch (e) {
// Do nothing, just preventing error
}
@maximblack That would work just as fine. Don't forget to change to multiline comments, else the last bracket gets blown off :smile:
@maximblack , @ooade Thank you!
Just ran into this. Wanted to just say that I'd love to see some kind of initialization infrastructure in next.js. Having a simple place (not _document.js!) to put server-only and client-only init code would be fantastic. Having hooks that only ran once on the server and client, as well as hooks that allowed for easy decorating of pages, both on the server and client, would be really fantastic.
@arunoda I am still having issues with this. I've been calling it on the top of my file and not having any issues running in dev but as soon as I try to run next build
it can't find the module. It seems to have something to do with react-dom
errors:
[ './~/react-tap-event-plugin/src/injectTapEventPlugin.js\nModule not found: Error: Can\'t resolve \'react-dom/lib/EventPluginHub\' in \'\\node_modules\\react-tap-event-plugin\\src\'\nresolve \'react-dom/lib/EventPluginHub\' in \'\\node_modules\\react-tap-event-plugin\\src\'\n Parsed request is a module\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n aliased with mapping \'react-dom\': \'\\node_modules\\react-dom\\dist\\react-dom.min.js\' to \'\\node_modules\\react-dom\\dist\\react-dom.min.js/lib/EventPluginHub\'\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n after using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n using description file: \\node_modules\\react-dom\\package.json (relative path: ./dist/react-dom.min.js/lib/EventPluginHub)\n no extension\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginHub doesn\'t exist\n .js\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginHub.js doesn\'t exist\n .json\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginHub.json doesn\'t exist\n as directory\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginHub doesn\'t exist\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginHub]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginHub.js]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginHub.json]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginHub]\n @ ./~/react-tap-event-plugin/src/injectTapEventPlugin.js 23:2-41\n @ ./components/shared/Layout.js\n @ ./pages/discover.js?entry\n @ multi ./pages/discover.js?entry',
'./~/react-tap-event-plugin/src/TapEventPlugin.js\nModule not found: Error: Can\'t resolve \'react-dom/lib/EventConstants\' in \'\\node_modules\\react-tap-event-plugin\\src\'\nresolve \'react-dom/lib/EventConstants\' in \'\\node_modules\\react-tap-event-plugin\\src\'\n Parsed request is a module\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n aliased with mapping \'react-dom\': \'\\node_modules\\react-dom\\dist\\react-dom.min.js\' to \'\\node_modules\\react-dom\\dist\\react-dom.min.js/lib/EventConstants\'\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n after using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n using description file: \\node_modules\\react-dom\\package.json (relative path: ./dist/react-dom.min.js/lib/EventConstants)\n no extension\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventConstants doesn\'t exist\n .js\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventConstants.js doesn\'t exist\n .json\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventConstants.json doesn\'t exist\n as directory\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventConstants doesn\'t exist\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventConstants]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventConstants.js]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventConstants.json]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventConstants]\n @ ./~/react-tap-event-plugin/src/TapEventPlugin.js 22:21-60\n @ ./~/react-tap-event-plugin/src/injectTapEventPlugin.js\n @ ./components/shared/Layout.js\n @ ./pages/discover.js?entry\n @ multi ./pages/discover.js?entry',
'./~/react-tap-event-plugin/src/TapEventPlugin.js\nModule not found: Error: Can\'t resolve \'react-dom/lib/EventPluginUtils\' in \'\\node_modules\\react-tap-event-plugin\\src\'\nresolve \'react-dom/lib/EventPluginUtils\' in \'\\node_modules\\react-tap-event-plugin\\src\'\n Parsed request is a module\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n aliased with mapping \'react-dom\': \'\\node_modules\\react-dom\\dist\\react-dom.min.js\' to \'\\node_modules\\react-dom\\dist\\react-dom.min.js/lib/EventPluginUtils\'\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n after using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n using description file: \\node_modules\\react-dom\\package.json (relative path: ./dist/react-dom.min.js/lib/EventPluginUtils)\n no extension\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginUtils doesn\'t exist\n .js\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginUtils.js doesn\'t exist\n .json\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginUtils.json doesn\'t exist\n as directory\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginUtils doesn\'t exist\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginUtils]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginUtils.js]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginUtils.json]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPluginUtils]\n @ ./~/react-tap-event-plugin/src/TapEventPlugin.js 23:23-64\n @ ./~/react-tap-event-plugin/src/injectTapEventPlugin.js\n @ ./components/shared/Layout.js\n @ ./pages/discover.js?entry\n @ multi ./pages/discover.js?entry',
'./~/react-tap-event-plugin/src/TapEventPlugin.js\nModule not found: Error: Can\'t resolve \'react-dom/lib/EventPropagators\' in \'\\node_modules\\react-tap-event-plugin\\src\'\nresolve \'react-dom/lib/EventPropagators\' in \'\\node_modules\\react-tap-event-plugin\\src\'\n Parsed request is a module\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n aliased with mapping \'react-dom\': \'\\node_modules\\react-dom\\dist\\react-dom.min.js\' to \'\\node_modules\\react-dom\\dist\\react-dom.min.js/lib/EventPropagators\'\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n after using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n using description file: \\node_modules\\react-dom\\package.json (relative path: ./dist/react-dom.min.js/lib/EventPropagators)\n no extension\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPropagators doesn\'t exist\n .js\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPropagators.js doesn\'t exist\n .json\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPropagators.json doesn\'t exist\n as directory\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPropagators doesn\'t exist\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPropagators]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPropagators.js]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPropagators.json]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\EventPropagators]\n @ ./~/react-tap-event-plugin/src/TapEventPlugin.js 24:23-64\n @ ./~/react-tap-event-plugin/src/injectTapEventPlugin.js\n @ ./components/shared/Layout.js\n @ ./pages/discover.js?entry\n @ multi ./pages/discover.js?entry',
'./~/react-tap-event-plugin/src/TapEventPlugin.js\nModule not found: Error: Can\'t resolve \'react-dom/lib/SyntheticUIEvent\' in \'\\node_modules\\react-tap-event-plugin\\src\'\nresolve \'react-dom/lib/SyntheticUIEvent\' in \'\\node_modules\\react-tap-event-plugin\\src\'\n Parsed request is a module\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n aliased with mapping \'react-dom\': \'\\node_modules\\react-dom\\dist\\react-dom.min.js\' to \'\\node_modules\\react-dom\\dist\\react-dom.min.js/lib/SyntheticUIEvent\'\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n after using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n using description file: \\node_modules\\react-dom\\package.json (relative path: ./dist/react-dom.min.js/lib/SyntheticUIEvent)\n no extension\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\SyntheticUIEvent doesn\'t exist\n .js\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\SyntheticUIEvent.js doesn\'t exist\n .json\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\SyntheticUIEvent.json doesn\'t exist\n as directory\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\SyntheticUIEvent doesn\'t exist\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\SyntheticUIEvent]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\SyntheticUIEvent.js]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\SyntheticUIEvent.json]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\SyntheticUIEvent]\n @ ./~/react-tap-event-plugin/src/TapEventPlugin.js 25:23-64\n @ ./~/react-tap-event-plugin/src/injectTapEventPlugin.js\n @ ./components/shared/Layout.js\n @ ./pages/discover.js?entry\n @ multi ./pages/discover.js?entry',
'./~/react-tap-event-plugin/src/TapEventPlugin.js\nModule not found: Error: Can\'t resolve \'react-dom/lib/ViewportMetrics\' in \'\\node_modules\\react-tap-event-plugin\\src\'\nresolve \'react-dom/lib/ViewportMetrics\' in \'\\node_modules\\react-tap-event-plugin\\src\'\n Parsed request is a module\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n aliased with mapping \'react-dom\': \'\\node_modules\\react-dom\\dist\\react-dom.min.js\' to \'\\node_modules\\react-dom\\dist\\react-dom.min.js/lib/ViewportMetrics\'\n using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n Field \'browser\' doesn\'t contain a valid alias configuration\n after using description file: \\node_modules\\react-tap-event-plugin\\package.json (relative path: ./src)\n using description file: \\node_modules\\react-dom\\package.json (relative path: ./dist/react-dom.min.js/lib/ViewportMetrics)\n no extension\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\ViewportMetrics doesn\'t exist\n .js\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\ViewportMetrics.js doesn\'t exist\n .json\n Field \'browser\' doesn\'t contain a valid alias configuration\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\ViewportMetrics.json doesn\'t exist\n as directory\n \\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\ViewportMetrics doesn\'t exist\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\ViewportMetrics]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\ViewportMetrics.js]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\ViewportMetrics.json]\n[\\node_modules\\react-dom\\dist\\react-dom.min.js\\lib\\ViewportMetrics]\n @ ./~/react-tap-event-plugin/src/TapEventPlugin.js 27:22-62\n @ ./~/react-tap-event-plugin/src/injectTapEventPlugin.js\n @ ./components/shared/Layout.js\n @ ./pages/discover.js?entry\n @ multi ./pages/discover.js?entry',
'commons.js from UglifyJs\nInvalid assignment [commons.js:18983,31]' ],
warnings: [] }
I think with the above solution it imports correctly without errors but the plugin itself does nothing. Internally it tries to hook into React's event system, but with Next.js this fails silently (does nothing).
I don't think modules that hook into the event system will work with next.js at all
Most helpful comment
@EehMauro there's a simple fix for this.
Add following content to a file in
components/tap_events.js
Then import it inside each of your pages like this: