Why does my ReactJS export statement not work? - javascript

I'm ultimately trying to dynamically create an object of imported components to export all at once. But in my simple example below, I can't even export an object with 1 component. Why is that?
// index.js
// Card is a standard ReactJS component, exported with export default Card
import Card from './Card';
let Components = {};
Components['Card'] = Card;
// this also doesn't work
// Components['Card'] = require('./Card').default
export default Components;
// Error message: "Attempted import error: 'Card' is not exported from './index.js'"

As the error says, you don't have a named export Cards. You have a default export, Components, which is an object with a property Cards.
If you want to have named export Cards then do
export {Cards};
Or if you don't even need the Components object, you can re-export the component directly with
export {default as Card} from './Card';
However if you really do want to export a default object that holds one or more components as properties, then import it accordingly:
import Components from './index.js';
// use Components.Cards were necessary
See the export documentation on MDN for more information.

Two solution here. Firstly when you assign a component into the Components object you can assign Card as a component like below.
Components['Card'] = <Card/>
and then use it like this
<div>{Components.Card}</div>
Secondly and My favorite is, whatever you have done in the index.js file to store the component is ok. But when you are using it use it like below.
<Component.Card/>
Example

Related

How to dynamically import an object exported from another file?

In my node_modules, I have a folder with an index.js which exports an object which contains a bunch of icon objects.
export { arrow1, arrow2, arrow3 .. }
I want to somehow dynamically import an icon object from another component. I am using Stencil.js, which is similar to React, and I need to use the icon string passed as a prop to dynamically import that particular icon object. How do I do that? The issue is that the import statement must be at the top of the page, but the prop is defined below.
Is there a way to import an exported object without using the import statement?
I tried with fetch() but it wasn't working. It kept returning status not ok.
I don't see point how importing all icons is a performance issue.
Here is small example, but it depends on what format are the imported icons.
import { IconNames } from '../icon/types';
#Component({
tag: 'custom-component'
})
export class CustomComponent {
#Prop() iconName: keyof IconNames;
render() {
const unicodeIcon = String.fromCharCode(parseInt(getIconHexCharCode(this.iconName), 16));
return (
<span>{unicodeIcon}</span>
)
}
}

Import methods of the components instead of the binding function

export default withModalMounter(injectIntl(Poll));
I want to extract Poll while importing it in a different component. It looks that that while importing I am just able to import withModalMounter component and not the methods of Poll.
Since you want to import Poll component without withModalMounter too. You can export it like below
const withInjectIntl = injectIntl(Poll);
export { withInjectIntl as Poll };
export default withModalMounter(withInjectIntl);
Post this you can import it like
import PollWithMounter, { Poll } from 'path/to/poll';

How to wrap every exported comopnent with HOC?

I need to add to ALL of my React function components the possibility to add [data-test-id] attribute for testing purposes. To achieve that I created withTestId() HOC which adds optional prop testId to wrapped component and when it's defined it adds [data-test-id] to final HTML.
So when I define component like:
<ExampleComponent testId="example" />
it returns:
<div data-test-id="example" />
The only problem I have is to apply it to every component without the necessity to wrap it individually in every component. So instead of writing code like:
function ExampleComponent() { ... }
export default withTestId(ExampleComponent)
I would like to wrap all of my exports in my index.ts file, which right now looks like this:
export { default as ExampleComponent } from "./ExampleComponent";
export { default as ExampleComponent2 } from "./ExampleComponent2";
...
How can I achieve this?
I see two ways of doing this; One dynamic way, making the user-code of your library a bit more convoluted. with you being able to change the implementation easily and another one with a bit more boilerplate code, keeping the user-code as it is.
I haven't tested their behavior regarding tree-shaking when bundling the code.
Using destructing in user-code
This allows to add / remove things from your main component export file without having to worry about additional boilerplate in your library. The higher-order-component can be switched on/off easily. One caveat: The user code needs to use destructuring to retrieve the components.
Your new index.ts file would look like this, while I've called your previous index.ts file components.ts in the same directory:
import * as RegularComponents from "./components";
import withTestId from "./with-test-id";
const WithTestIdComponents = Object
.keys(RegularComponents)
.reduce((testIdComps, key) => {
return {
...testIdComps,
[key]: withTestId(RegularComponents[key])
};
}, {});
export default WithTestIdComponents;
To use it in your application code:
import MyComponents from "./components/tested";
const { Component1, Component2, Component3, Component4 } = MyComponents;
This uses the default export to make it look like you have all components in one place, but since you cannot destructure exports directly, you need this second step to get the correct components out of it.
Add boilerplate to the export file
Since there is an index.ts file with all the components exported in the library, one could import/rename each component and re-export them with withTestId and their name:
import withTestId from "./with-test-id";
import { default as TmpComponent1 } from "./component1";
import { default as TmpComponent2 } from "./component2";
import { default as TmpComponent3 } from "./component3";
import { default as TmpComponent4 } from "./component4";
export const Component1 = withTestId(TmpComponent1);
export const Component2 = withTestId(TmpComponent2);
export const Component3 = withTestId(TmpComponent3);
export const Component4 = withTestId(TmpComponent4);
This way, imports can be used as before:
import {
Component1,
Component2,
Component3,
Component4
} from "./components";
I'd argue that using index files already is some kind of boilerplate and this approach adds to it. Since the user code does not need any changes, I'd favor this approach.
In one of our projects, we have used a custom takeoff script to create this kind of boilerplate for us, whenever we generate a new component.
Examples
Here is a code sandbox to see both approaches.

Unable to export 2 Higher Order Components from one JS file in ReactJS

I have 2 Components in a file and I am trying to supercharge them and export them as HOCs.
export default withStyles(styles)(Component1);
export withStyles(styles)(Component2);
But, I am getting error on second export. However, if I change it to:
export Component2OtherWay = withStyles(styles)(Component2);
Then, it is working fine. Could anyone explain this to me?
Cheers!
Since the second export is a named export you need to give it a name which is why you are getting the error.
A file can have only one default export and you need to not give a name to the component exported as default but for a named export you need to give a name which is what the second syntax does
export const Component2OtherWay = withStyles(styles)(Component2);
Also a named export can be imported like
import { Component2OtherWay } from 'path/to/Component';
The default keyword has nothing to do with multiple exports. It's just a name. It’s exported under default name.
So you need another name to export next component.

Named import in React

In this line:
import React, { Component } from "react";
why the braces are only around Component and not also on 'React'?
Here's a great answer that explains default and named imports in ES6
Let's say we have a class named Foo that I want to import. If I want to get the default export, I would do:
import Foo from './foo.js';
If I wanted a specific function inside the foo file, I would use the curly braces.
import { fooFunction } from './foo.js';
Note, this isn't a React feature, but ES6. Likely you are using babel to transpile your code from ES6 to ES5.
To create something similar in react. Lets take this following example.
someobject.js
const someobject = {
somefunc1: ()=>console.log("hello 1"),
somefunc2: ()=>console.log("hello 2")
}
export default someobject;
app.js
import someobject, { somefunc1, somefunc2 } from "./someobject";
someobject.somefunc1(); //hello 1
someobject.somefunc2(); //hello 2
somefunc1(); //hello 1
somefunc2(); //hello 2
export defaul
In the React module the default export is the React object and it also has a named export Component1, something like this:
// assuming React and Component are predefined
export default React
export Component
Coincidentally Component is also available on the React object, so it is not necessary to import separately, although some people prefer your approach. For example this is possible:
// MyComponent.js
import React from 'react'
class MyComponent extends React.Component {}
More information about ES6 module syntax can be found here.
1 Note that actually the React library does not have a named export Component as in the example above, however Component is a property on the default export and so due to the way that ES6 packages are transpiled by Babel, this becomes a named export, the behaviour then being as in the example above.
Import react will import the default react package, Component with braces then specifies a particular element of the React package. React by default will not need braces as it is the default import package.
import React, { Component } from "react";
Hope this helps
That is because the default export module in the react library is React, and there can be only one default export, even though you can export many other components, but only one can be default. Other components of the React library can then be destructured.
React is a module containing different methods, When using just React word, you import the whole module, so you can use React.Component (in this case dot notation reference to a method inside the module).
So if you need to import method? you will use braces, why?
because you import method between many methods in one module, So it's able to increase & decrease, so you can import {a, b, c, r, w, q} that's methods inside one class or one module, So you can see that if you using
import {Component} from 'react';
Now you can use Component word direct without dot reference like react.component.
So React module is exported by default, Here I need all the React module and I will use it with all methods, {Component} here exported by name, I need specific method from React library not all react library
and please check it too When should I use curly braces for ES6 import?
in the import import React, { Component } from "react"; we put the Component in braces because it is not the default export. however React is,... look at the following example
import React from "react";
export const Fun1 = () => {
return (
<React.Fragment>
<h1>this is fun 1</h1>
</React.Fragment>
);
};
export const Fun2 = () => {
return (
<React.Fragment>
<h1>this is fun 2</h1>
</React.Fragment>
);
};
const Fun3 = () => {
return (
<React.Fragment>
<h1>this is fun 3</h1>
</React.Fragment>
);
};
export default Fun3;
if we save the above file under example.js we can import the components in exmpample.js file as
import Fun3, {Fun1, Fun2} from "example";
therefore Fun3 is the default export and the other components Fun1 and Fun2 are not

Categories

Resources