Closed xiaohuoni closed 5 years ago
What are you expecting from this module on web? Please can you fill out the issue template as required, then I'll reopen this.
@necolas look this!
Thank you.
Please can you include an example of the code you have that is causing the error? Is it in a dependency or your own code? What events are you listening to and what do you do after the events are emitted?
export default class ModalTarget extends Component {
static add(modal) {
const modalKey = ++keyValue;
DeviceEventEmitter.emit('addModals', { modalKey, modal });
return modalKey;
}
constructor(props) {
super(props);
this.state = {
modals: [],
};
}
componentWillMount() {
DeviceEventEmitter.addListener('addModals', event => this.add(event));
}
componentWillUnmount() {
DeviceEventEmitter.removeAllListeners('addModals');
}
add(event) {
const { modals } = this.state;
modals.push(event);
this.setState({ modals });
}
render() {
const { modals } = this.state;
return (
<View style={{ backgroundColor: Theme.fill_grey, flex: 1 }}>
{this.props.children}
{modals.map(item => (
<View key={`modals${item.key}`} >
{item.modal}
</View>
))}
</View>
);
}
}
i can use ModalTarget.add demo :https://github.com/xiaohuoni/whale-rn/
@necolas Hello,Do you have any development plan? Or do you have any plans to consider?
Yes I'll review a PR for this.
This article says it's best to use NativeEventEmitter
so that needs to be added too https://levelup.gitconnected.com/react-native-events-in-gory-details-what-happens-on-the-way-to-listeners-2cee6c55940c
@necolas
import events from "events";
const { EventEmitter } = events;
const DeviceEventEmitter = new EventEmitter();
export default DeviceEventEmitter;
I use the code in my project.It works very well. Because I think on web, it only needs js2js.
oh, @necolas , want to use react-native-modal
but it raise:
index.js:1 Uncaught TypeError: Cannot read property 'addListener' of undefined
yes, DeviceEventEmitter
not here
how to solve this error undefined is not an object(evaluating 'subscription.listener.appy') ?
This article says it's best to use NativeEventEmitter so that needs to be added too...
AFAIK Turbo modules will change a lot of emitter functionality works so it may not make sense to start supporting it now.
I have the same problem when i use react-native-web on RN project. When i new NativeEventEmitter(), it will throw an error on platform ios. Can solve this problem
Thanks for that work Evan, that's a real help!
Here's how I'm consuming react-native-modal
(which consumes NativeEventEmitter) in a project created using a boilerplate for React Native Web based on create-react-app
(not Expo Web).
DeviceEventEmitter
I installed Evan Bacon's fork of React Native Web that implements a PR for re-exporting DeviceEventEmitter. This PR has been merged into Expo for Web already, but has not yet been merged into React Native Web:
git clone https://github.com/EvanBacon/react-native-web.git
cd react-native-web
git checkout "@evanbacon/plugins/DeviceEventEmitter"
yarn install
yarn compile
cd packages/react-native-web
pwd
# This is the filepath to the React Native Web package under the React Native Web monorepo (GitHub project)
# Now in your RNW project, run `yarn remove react-native-web && yarn add <that filepath>`
I examined Expo for Web's webpack config, and adapted my Create React App's webpack config to incorporate the necessary changes to support NativeEventEmitter (in addition to the usual react-native-web
babel plugin).
I customised the Create React App webpack config using rescripts
(hence the .rescriptsrc.js
file), but Customize React App would also work.
// .rescriptsrc.js
const path = require('path');
const { getPaths, edit, getWebpackPlugin, paths } = require('@rescripts/utilities');
module.exports = config => {
const isEnvDevelopment = config.mode === "development";
const isEnvProduction = config.mode === "production";
config.resolve.alias = {
...config.resolve.alias,
/* https://github.com/expo/expo-cli/blob/72e35aea644ce38a5389595f3ff18b45454d7986/packages/webpack-config/webpack/webpack.common.js#L312-L322 */
// Alias internal react-native modules to react-native-web
'react-native/Libraries/Components/View/ViewStylePropTypes$':
'react-native-web/dist/exports/View/ViewStylePropTypes',
'react-native/Libraries/EventEmitter/RCTDeviceEventEmitter$':
'react-native-web/dist/vendor/react-native/NativeEventEmitter/RCTDeviceEventEmitter',
'react-native/Libraries/vendor/emitter/EventEmitter$':
'react-native-web/dist/vendor/react-native/emitter/EventEmitter',
'react-native/Libraries/vendor/emitter/EventSubscriptionVendor$':
'react-native-web/dist/vendor/react-native/emitter/EventSubscriptionVendor',
'react-native/Libraries/EventEmitter/NativeEventEmitter$':
'react-native-web/dist/vendor/react-native/NativeEventEmitter',
};
/* With reference to: https://github.com/arackaf/customize-cra/blob/master/src/utilities.js */
const babelLoaderForSrcPaths = getPaths(
inQuestion => {
if(inQuestion && inQuestion.loader && inQuestion.loader.includes('babel-loader')){
/* This distinguishes the two babel-loaders: here we select the one for src rather than node_modules. */
return inQuestion.include === paths.src; /* Where paths.src is 'our' reference to paths.appSrc. */
}
return false;
},
config
);
/* With reference to: https://github.com/arackaf/customize-cra/blob/master/api.md#babelinclude */
config = edit(
(babelLoaderForSrc) => {
babelLoaderForSrc.include = [
// make sure you link your own source
path.resolve("src"),
// From react-native-modal
path.resolve("node_modules/react-native-modal"),
path.resolve("node_modules/react-native-animatable"),
];
babelLoaderForSrc.options.plugins.push(
["react-native-web", { commonjs: true }],
);
return babelLoaderForSrc;
},
babelLoaderForSrcPaths,
config
);
/* The CRA config defines process.env with an extra layer of quotes on values, and so so shall we.
* This substitutes for the global variables normally injected by the Metro bundler:
* https://github.com/facebook/metro/blob/1f9a557e892716dffe9ffa250e0c62c2a65a0bdb/packages/metro/src/lib/getPreludeCode.js#L22
* I had expected metro-react-native-babel-preset to do this for us, but I guess it doesn't.
* DefinePlugin docs: https://webpack.js.org/plugins/define-plugin/ */
const definePlugin = getWebpackPlugin("DefinePlugin", config);
Object.assign(
definePlugin.definitions,
{
/* Just because it's defined globally doesn't mean that window links to it, so we define both here (it's not redundant).
* However, technically no React code references window.__DEV__ in practice; we shouldn't really look for it on window ourselves either. */
__DEV__: `${isEnvDevelopment}`,
"window.__DEV__": `${isEnvDevelopment}`,
}
);
return config;
};
This may not be totally ready for use, as Evan notes in https://github.com/necolas/react-native-web/pull/1402 that there are still to-dos to complete. I don't know. And either way, DeviceEventEmitter will be changing due to TurboModules, so this method may soon become irrelevant. But if you need something working right now, here's an option.
8f5e7d4e1468abe028cfab339e275097ceb75d3e
An update to my previous advice: no need to install Evan Bacon's fork for this feature now, as it's been merged into the core. Just installing "react-native-web": "0.11.6"
suffices (my Webpack instructions still apply).
DeviceEventEmitter supported on web. How to use DeviceEventEmitter in web is just a emit event between pages.
Is your feature request related to a problem? Please describe. When I transferred an old RN project to web, I used the DeviceEventEmitter in the RN project, so I reported the wrong https://github.com/necolas/react-native-web/issues/841
Describe a solution you'd like Use DeviceEventEmitter.emit in Web
Describe alternatives you've considered eventemitter3 Additional context