Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

importing throws error unless index is specified #12539

Closed
rhysburnie opened this issue Feb 23, 2017 · 10 comments

Comments

Projects
None yet
6 participants
@rhysburnie
Copy link

commented Feb 23, 2017

Hi,

This is weird...

I have a file app/index.js with:

import React from 'react';
import { View, Text } from 'react-native';
export const App = () => (
  <View>
    <Text>The App</Text>
  </View>
);
export default App;

In this case I should be able to do either import App from './app' or import { App } from './app' and use it in my AppRegistry.registerComponent.

However I get the following error unless I import the path ./app/index which you should not need to do.

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object

Versions installed, osx siera, node v7.5.0:

react-native-cli: 2.0.1
react-native: 0.41.2

This is the first I have ever come across having to specify index is this a known issue?

@der-kua

This comment has been minimized.

Copy link

commented Feb 23, 2017

+1

@rhysburnie

This comment has been minimized.

Copy link
Author

commented Feb 24, 2017

After trying system reboot etc I also tried importing the file both ways under two variable names so I could see what is being returned:

index.ios.js:

import React, { Component } from 'react';
import { AppRegistry } from 'react-native';

import AppImport1 from './app';
import AppImport2 from './app/index';

import { View, Text } from 'react-native';

const container = {
	flex: 1,
	justifyContent: 'center',
};

export const LocalApp = () => (
  <View style={container}>
    <Text>AppImport1:</Text>
		<Text>type: {typeof AppImport1}</Text>
		<Text>{JSON.stringify(AppImport1, null, 2)}</Text>
		<Text>AppImport2:</Text>
		<Text>type: {typeof AppImport2}</Text>
		<Text>{JSON.stringify(AppImport2, null, 2)}</Text>
  </View>
);

AppRegistry.registerComponent('TestApp', () => LocalApp);

Result:

AppImport1 (the failing import)

type: object
{
  "name": "TestApp",
  "displayName": "TestApp"
}
  • no idea where the build system is getting that from its clearly not in the ./app/index.js

AppImport2 (correct but requires full path which you should never need in node ie. ./app/index

type: function

Also tried a class in the ./app/index.js made no difference

class App extends Component {
	render () {
		return (
		  <View>
		    <Text>The App</Text>
		  </View>
		);
	}
}
@brentvatne

This comment has been minimized.

Copy link
Collaborator

commented Feb 24, 2017

This issue is a little bit confusing, can you post an example project that repros it?

import React from 'react';
import { AppRegistry } from 'react-native';

import MyApp from './app';
import { App } from './app';
AppRegistry.registerComponent('main', () => MyApp);
// AppRegistry.registerComponent('main', () => App);
// app/index.js

import React from 'react';
import { View, Text } from 'react-native';
export const App = () => (
  <View>
    <Text>The App</Text>
  </View>
);
export default App;

This works exactly as expected. I imagine you probably forgot to add the function wrapper around the second param in AppRegistry.registerComponent, so it invoked the functional component and returned the result, which is the result of rendering, rather than the component itself.

Feel free to create a new issue with a minimal example project that clearly demonstrates the problem if this isn't it :)

@brentvatne brentvatne closed this Feb 24, 2017

@rhysburnie

This comment has been minimized.

Copy link
Author

commented Feb 26, 2017

@brentvatne nope did not forget function wrapper.

index.ios.js

import React from 'react';
import { AppRegistry } from 'react-native';

import App from './app';

// only the following import works...
// import App from './app/index';

AppRegistry.registerComponent('TestApp', () => App);

./app/index.js

import React from 'react';
import { View, Text } from 'react-native';

export const App = () => (
  <View>
    <Text>The App</Text>
  </View>
);

export default App;

The project started via react-native init TestProject. Only those two files created / edited can't be any simpler than that.

As stated unless the full index path used the default isn't imported instead it is an object instead of the expected component

If I inspect what is imported using import App from './app'; it is indeed an object as the error indicates with the following properties:

{
  "name": "TestApp",
  "displayName": "TestApp"
}

Clearly the ./app/index.js does not contain that object, there is obviously something going wrong with the build hence the raised issue.

The entire point of this issue is the fact that it should work not that my syntax is incorrect, I would not post it before investigating. The file app/index file works fine when imported via full path, as we all know in node you should not need the full path to an index file.

It also made no difference if the exported default was a function or a class, it also made no difference if I instead imported a explicitly named component rather than default.

I intentionally only touched the two files mentioned everything else in the project is what is generated via react-native init I have the latest react-native and react-native cli, I have not installed any other third party dependency in the project.

In addition no other node project or web react project has this import issue.

I would not be surprised if it does work fine for you... That is my point... it makes no sense why it is not working, I had no issues last time I used react-native. I have tried basic stuff I can think of, updating react-native, yarn, node, I've kept it incredibly simple so nothing else could be influencing it.

I've restarted my machine and then run nothing but terminal, my ide (atom) and the react-native commands but still nothing changes it simply won't import a perfectly valid es6 file default unless the full index path is specified.

Heres a temp repo (tho the code for the two files have been posted here anyway) https://github.com/rhysburnie/TempBugReportSetup

@rhysburnie

This comment has been minimized.

Copy link
Author

commented Feb 26, 2017

Further to this - if I copy the ./app/index.js file and use the same content in a subdirectory ./app/subfolder/index.js and then import from there import App from './app/subfolder'; then it works perfectly fine. File content exactly the same - makes no sense.

Then after the subfolder path working I tried renaming the app folder to shared, then importing import App from './shared'; worked.

So it seems like the combination of the folder name app with an index file results in the system importing the object mentioned before rather than the expected component.

  • import App from './app'; (fails to load ./app/index)
  • import App from './shared'; (loads ./shared/index fine)

both files exactly the same

if ./app/index is somehow reserved in react-native is that mentioned in documentation - if so where?

@rhysburnie

This comment has been minimized.

Copy link
Author

commented Feb 27, 2017

@brentvatne
FYI - Figured out what was happening...

If you have a file ./app/index.js and you attempt to import like so:

import Something from './app';

What actually happens is the system is importing the root level ./app.json file which contains the object in question.

So while this isn't a bug it is perhaps a gotcha?

It seems reasonable to expect that some developers may create an app folder and that they may create an index.js in that folder and expect it to import as expected.

The gotcha is that the system prefers ./app.json over ./app/index.js

@ujwal-setlur

This comment has been minimized.

Copy link

commented Aug 3, 2017

Got burned by this as well :-). Interestingly, it worked fine on android, but gave problems on ios. I just deleted app.json. Is it actually needed?

@mtrabelsi

This comment has been minimized.

Copy link

commented Feb 7, 2018

shit looks like a bad naming pattern that a lot of dev fall in - just renamed it to src

@ujwal-setlur

This comment has been minimized.

Copy link

commented Feb 8, 2018

Actually, I would not call it a bad naming pattern on the dev part, it's quite common to organize your code under app or src. I think react-native should have called their file rnapp.json since it's specific to react-native.

@rhysburnie

This comment has been minimized.

Copy link
Author

commented Feb 9, 2018

For me this was resolved months ago - just use another filename "entry.js"

It's hard to say what the app.json file is for (that is to say I don't care enough to find out), last time I opened it (a year ago) it seemed to contain redundant information that is present in the package.json anyway. However as per @ujwal-setlur comment RE deleting the file affecting ios and not android I'm guessing it may be required by apple and perhaps the name "app.json" is also required?

Seems simpler to just use another name for your entry point. A heads up in the docs would avoid future confusion.

@facebook facebook locked as resolved and limited conversation to collaborators May 24, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.