I am working with a React project where each component's files are contained in their own directory. I have a component.jsx file and an index.js file that re-exports the component's default export. This works as expected. I would like to simplify my import statements by re-exporting all components up directory level from the main components folder. See below for an example of my current project foloder structure.
src
--components
----Alert
------Alert.jsx
------index.js
----LoginCard
------LoginCard.jsx
------index.js
--index.js
Alert/Alert.jsx
export default function Alert(props) {
// omitted for brevity - the component itself works fine
return <Alert />
}
Alert/index.js
export { default } from './Alert';
At this point, imports work as expected in the LoginCard component.
LoginCard.jsx
import { UserContext } from '#contexts';
import Alert from '#components/Alert';
export default function LoginCard(props) {
// omitted for brevity. Again, component works as expected
return <LoginCard />
In order to achieve my desired end result of simplifying import calls, I created components/index.js:
components/index.js
export { default as Alert } from './Alert';
Which I then attempt to import as:
LoginCard.jsx
import { Alert } from '#components'
When attempting to import from component/index.js as import { Alert} from '#components' I receive an exception that states "cannot read default property of undefined". What makes this strange is that I import/export my pages and contexts in exactly the same manner and they work as expected. I originally thought that this implied an issue with my components directory alias, but the alias is working as I can import just fine from #components/Alert, just not from #components
Have a missed something simple, or am I hitting a bug? Thanks.
I think the issue here is that you are attempting to push all the exports up the tree towards the root directory. This makes sense when importing somewhere outside that root directory. The issue lies in the fact that you are attempting to import from the root while inside the directory structure. In other words, all the exports from within the directory need to be processed before anything can be exported from the root.
The snag here is that you are attempting to import Alert from the root export from LoginCard... which while being processed hasn't finished its exports, so the root export isn't ready yet.
In other words, #components/Alert is ready, #components is not.
Just use a relative import of Alert (and any other import) from within the same components directory.
import { UserContext } from '#contexts';
import Alert from '#components/Alert';
// or
import Alert from '../Alert';
export default function LoginCard(props) {
// omitted for brevity. Again, component works as expected
return <LoginCard />
Related
This is my folder hierarchy-
SRC -
/assets
/components
App.jsx
COMPONENTS -
/screens/Login.jsx
Carousel.jsx
Navbar.jsx
Suppose I am in the Login.jsx file. From there how will I import a context which was declared in App.jsx
When I start writing this code -
import React from 'react';
import { IsLoggedInContext } from '../'
The autocompletes in vscode editor I get are -
Carousel
Navbar
Screens
When I start using .../ no autocomplete comes for the App file and it doesn't also work if I manually write this code -
import { isLoggedInContext } from '.../App'
So, how will I import the context in the Login.jsx file? Is there any way?
A single . is the current directory, a double .. is the parent directory. A triple ... isn't valid syntax for referencing directory/file structures.
From src/components/screens, ".." gets you into src/components, and "../.." gets you up another level back to src.
import { isLoggedInContext } from '../../App';
In React when you wanna import components from other files we use:
import ComponentName from 'somePlace';
That works fine, but I wanna know if there is a way to import the content of a file instead of the exports. I wanna put all import statements for components in a single file (e.g. imports.js) and have a statement like:
import './import.js' to all documents;
so all my components are automatically imported everywhere.
Is there a way to do that?
Globally import modules? Not really, no. And neither should you need to.
A hacky "solution" would be assigning all imports to the global context (e.g. window in the browser) so it's accessible that way. That's possible, but definitely not recommended. It'll also prevent your bundler (most likely Webpack) from optimizing a lot of code.
Apart from the technical aspect, there are other reasons not to do so. If you specify the imports in each file, you know exactly what imports that file needs and under what variables it is imported as for that file.
If you still want to simplify importing the same components over and over again, you can have this setup:
imports.js
// For default exports
import ComponentA from 'wherever';
export { ComponentA };
// For regular exports
//import { ComponentB } from 'wherever';
export { ComponentB } from 'wherever';
// For whole modules
//import * as wherever from 'wherever';
export * as wherever from 'wherever';
someOtherFile.js
// Either import as a namespace
import * as Imports from './imports';
console.log([
Imports.ComponentA,
Imports.ComponentB,
Imports.wherever.someFieldFromTheWhereverModule,
]);
// Or partial import
import { ComponentA, ComponentB } from './imports';
I have the following structure for my JS components:
/components
/Menu
/Menu.js
/Menu.test.js
/index.js
/MenuItem
/MenuItem.js
/MenuItem.test.js
/index.js
The idea being we can have a folder for each component that can contain a test (and possible other files) and then if we just want to import the component we can rely on the use of the index.js to handle the directory import without having to reference the class inside the folder direct.
So for example:
Menu.js
class Menu extends Component {
// ... more code ..
}
export default Menu;
index.js
export default from './Menu';
And then it can be used like:
import Menu from './components/Menu';
However I found that this didn't work and it couldn't find the module...
So to fix this I had to import Menu into the index.js before export:
import Menu from './Menu';
export default Menu;
But having looked at how other projects have structured their code, I have seen that they are using the former without having to import again...
For example: https://github.com/IBM/carbon-components-react/blob/master/src/components/Breadcrumb/index.js
See how they have exported from the Breadcrumb without having to do the import first... how have they achieved this?
If you check the provided example, you will see they use
this babel plugin.
So you can add one to your babel plugin stack.
Alternatively, you can look into using just export {default} from "./destination"; form which works as is.
For context, let me try to explain a little more.
In my project I have a folder, as example, for components.
Inside that folder I have my components files, and an index.js file where I import all the components and export than in the same line as follows:
export { default as Button } from './button'
export { default as Loader } from './loader'
export { default as ImageBackground } from './image-background'
So than I can import these components in Screen Component like that:
import { Button, Loader, ImageBackground } from 'src/components'
If I edit the components file, save and reload the project, everything works fine.
The problem is that when I edit any of these components with the Hot Module Replacement (Hot Reloading) actived, when it is triggered after an edit, it throws the following error:
Unhandled JS Exception: Requiring module "src/components/index.js", which threw an exception: TypeError: Cannot redefine property: Button
Has anyone have any idea why this is happening?
Thanks in advance!
Obs: When I import the component direct without using the index.js or if inside the index.js, I first import the component, than I assign the component to a variable and than I export this variable, it works fine.
my problem was solved when I changed render = () => (...) to render(){ return (...)} in react component
I'm trying to figure out an issue I have with ES6 modules import.
This is a very simplified version of what I'm attempting to do. My current file structure is much more complicated with nested folders.
I have 2 ReactJS components:
/buttons
/MyComponent1.js
/index.js
/texts
/MyComponent2.js
/index.js
/index.js
My files look something like this:
I'm importing the MyComponent2 from the root index.js file which is the entry-point of my package.
MyComponent1.js
import MyComponent2 from '../../';
export default () => (
<div><MyComponent2 /></div>
);
MyComponent2.js
export default () => (
<div>Hello world</div>
);
My buttons/index.js and texts/index.js files export all components in their own folder:
buttons/index.js
export { default as MyComponent1 } from './MyComponent1';
texts/index.js
export { default as MyComponent2 } from './MyComponent2';
And my root index.js export all my folders to make them publicly available. It's my entry-point:
export * from './buttons';
export * from './texts';
So when I import MyComponent2 in MyComponent1 from the root index.js file, it's undefined. When I import it from ./MyComponent2.js, it's defined. When I import the entire package in another project and import MyComponent2 from the root index.js file, it's defined.
It's mind-blowing and I don't understand why I can't import MyComponent2 from the root index.js file.
I need to do that because I have a set of hundred of components nested in different folder and I want to make them all available from this entry-point file.
Can someone tell me what is happening and how to make this possible?
Thanks
Okay, took me a while to figure out what is happening. Please take a look at the sandbox i've setup - https://codesandbox.io/s/nk0qmo096j
I've tried to keep the folder/module structure similar to what you've described. Please look through how the folder/modules are structured before you continue reading.
When you run the code in the sandbox, take a look at the console. You'll see something like this -
So let me try to explain why what you're trying to do is not working
buttons/MyComponent is the first file to be "exported" (since its at the bottom of the dependency chain; Project/index -> components/index -> buttons/index -> buttons/MyComponent)
Note that components/index has not been exported yet, so it will return undefined
Then buttons/index is exported, followed by texts/index
Then buttons/MyComponent is rendered; just before it is rendered i manually require components/index and it is now defined so returns some defined value
In essence, when your MyComponent1 is trying to import MyComponent2 via the index file, the index file has not been exported yet so it returns undefined. To work around this, you have to require MyComponent2 from within MyComponent1's render method.
you can import all the components from the respective component files and then assign them to a variable in the root component and then export all of them as objects.
import MyComponent1 from './buttons/index'
import MyComponent2 from './texts/index'
export {MyComponent1, MyComponent2}
to import this components in another file or project. you could import only one them using object destructuring.
import {MyComponent1} from 'index.js'
import {MyComponent2} from 'index.js'
In my case, I had an old js file that the IDE imported instead of the updated ts file. so if your module file is module.js make sure there isn't a compiled old module.js in the same directory