react context does not work when imported from relative part - javascript

I have monorepo with a UI library inside packages which contains a lot of components. Every component also has a *.stories.tsx file. Under the apps folder is the storybook project, which loads the stories from #my-ui-library.
I have a decorator in the storybook config, so my ThemeContextProvider is wrapped around everything (ThemeContextProvider is also imported from #my-ui-library).
Does not work:
button.tsx
import { ThemeContext } from '../../ThemeContext'
Does work:
button.tsx
import { ThemeContext } from '#my-ui-library'
Using the relative import I get the error that theme, which is stored in ThemeContext, is undefined.
Now, that itself wouldn't be a problem if VS Code wouldn't auto import from the relative path and I didn't have to change it manually everywhere.

Related

How to use code splitting with webpack in react app with components exported as export * from '...'

I'm trying to use code splitting in my react app and overall it works great, but I noticed something strange in bundle analyzer. My components folder is loaded in the first chunk with all its components (even the ones that are only used in lazy loaded components).
I think the problem is that I follow the structure of using index.ts files to export my components:
/components:
/Component1
/Child1
Child1.tsx
index.ts
Component1.tsx
index.ts
/Component2
Component2.tsx
index.ts
index.ts
The index.ts files just export the needed components like so
export * from './Component';
this is the same as
import { Component } from './Component';
export { Component };
in javascript.
By doing it that way I get very nice looking imports:
import { Component } from 'components';
without the deep paths and all that stuff.
But i think because of that webpack can not recognize how to split it and just bundles it all.
Are there any solutions for this? Maybe I'm doing something wrong?
I use the default create react app config right now.
export * from './Component';
This is causing webpack to bundle all the components which are there in './Component' and whatever it importing and so on.
You should export components individually without using *
Like export { Component1, Component2 } from './Component'
Also if you are using Webpack 5, it creates a mapping of which component import is used and discard unused components. This is not available in Webpack 4.

warning only in design view on import statement to use qml component from file

I have a .qml file with a component 2 steps above in my project path because I want to have a component folder above many projects to be shared by some of these. So in my main.qml I do:
import 'qrc:/../../components'
That works and I can use my qml component from file.
However in the design view, I get the warning:
found not working imports: ...<file and import line number where the import is> "qrc:/../../components": no such directory
Many other things I tried make the project not compile or throwns error at runtime.
Trial1: import "qrc:/": compile time error: Unknown component. (M300). Makes sense as the component is in a path above.
Trial2: import './../../components': runtime error: import "./../../components" has no qmldir and no namespace.
Tried also to put a qmldir file in my components folder where my component is with the text "MyComponent MyComponent.qml" as explained in Importing QML Document Directories
Apart from the warning everything works fine. Project compiles, runs and the changes in the component are shown when I work in the design view.
info:
-> component resource is added to the .qrc resource file, and the file exists (project works)
-> QtQuick version QtQuick 2.9
-> Qt Creator 4.15.2 Based on Qt 5.15.2
How do I get rid of the warning?
Edit: I also tried following the steps of this answer with no success.
Adding the content of my .qrc file:
<RCC>
<qresource prefix="/">
...<other not relevant resources>
<file>../../components/MyComponent.qml</file>
</qresource>
</RCC>
Screenshot of the warning:
Adding an alias for the file in your .qrc should resolve the issue, like so:
<file alias="MyComponent.qml">../../components/MyComponent.qml</file>
and then for your import statement simply:
import "qrc:/"
The alias should resolve whatever relative path issue is causing the warning to be thrown by the designer.

Cannot import Module without curly braces in react even after 'export default'

I have read somewhere that importing module in react with curly braces around imports the entire library instead and effectively increases the bundle size. I was using this concept and was successfull in importing modules without curly braces, like this:
import Jumbotron from 'reactstrap';
and it was working fine. I don't know why the next time I build the code, it started showing me this warning:
WARNING in ./React Coursera/Header.js 5:71-77
export default (imported as Jumbotron) was not found in reactstrap.
Also the app didn't run in browser.
Then I went to node_modules to check if export default is present in jumbotron or not, and I found this statement:
export default Jumbotron;
It means that indeed it was exporting the Jumbotron as default, then why it showed me this warning.
Can you help me guys to fix this problem?
Thanks in advance!
Where did you read that importing with curly will increase the bundle size, it's reverse,
// below line will import everything
import * as reactstrap from 'reactstrap'
But
// this will import only specific module
import { Jumbotron } from 'reactstrap'
By this line :
// will import from /reactstrap/index.js
import Jumbotron from 'reactstrap';
You are importing nothing https://github.com/reactstrap/reactstrap/blob/master/src/index.js , as there is export default
So I don't know how it worked before in your case
Below line :
// and this line is not inside the /reactstrap/index.js but /reactstrap/Jumbotron.js
export default Jumbotron;
is here : https://github.com/reactstrap/reactstrap/blob/master/src/Jumbotron.js
So you can do :
import { Jumbotron } from 'reactstrap'
It depends on your build setup and/or how the library code is setup. Some libraries are built in a way that won't import the entire library when you use curly braces. You can also have something enabled in your build tools called "tree shaking" which will remove all code that is unused.
I'm guessing what you were trying to do was import Jumbotron individually which is a safe bet when you are unsure if the whole lib will be imported. Again, it depends on the file structure of the library but you are probably missing the sub-directory in your import. There should be directories inside of the node_module folder for each component. Might be something like node_modules/reactstrap/Jumbotron. The default export you saw was probably on the Jumbotron file. When you use import Jumbotron from 'reactstrap' you are asking it do find a default export for the "main" file of the library. This would be defined in the package.json file of the library.
What you need to do is add the sub-directory to your import like so (just guessing here) import Jumbotron from 'reactstrap/Jumbotron'. Just think of reactstrap/ being the root directory of the library, you can select any file like you normally would.
If you are using webpack, there's this awesome plugin where you can check to see what is included in your bundles just to make sure you are indeed only importing the code that you need https://github.com/webpack-contrib/webpack-bundle-analyzer

how to handle the import hell in react?

I’m running my react app via Node. Is there a way to easily handle this import hell?
I’m running
./node_modules/.bin/babel-node --presets react,es2015 server/server.js
as npm start. And server.js is a simple Express Server that serves a ReactDOMServer.renderToString(<MyApp />)
Some of my react components have something like this:
import GenericTemplate from "../../templates/GenericTemplate/GenericTemplate";
import Footer from "../../organisms/Footer/Footer";
import Header from "../../organisms/Header/Header";
import Hero from "../../organisms/Hero/Hero";
import MainMenu from "../../organisms/MainMenu/MainMenu";
import TodoList from "../../organisms/TodoList/TodoList";
this is prone to error, one changement like directory name would result in manually entering every file to update this.
do you have any idea how I can fix this. Ideally I would have something like this:
import { Footer, Header, Hero, MainMenu, TodoList } from "myComponents"
is that possible? How?
Thank you!
This also doesn't look a lot better to me:
import { Footer, Header, Hero, MainMenu, TodoList } from "myComponents"
... because in order to do that, you need to export / import to "myComponents" every time you create a new component.
The core issue I see in your example is that using relative paths for imports makes your code base very hard to maintain.
To escape the "import hell" in React, one popular option is to make the import statements without relative paths.
With a minor tweak to your Webpack configuration, you can get it to load files relative to the app root. See here and read more here.
You can create a common components file in your organisms directory to achieve that. Just create a new common.js or whatever name with the following:
export Footer from "./Footer/Footer";
export Header from "./Header/Header";
export Hero from "./Hero/Hero";
export MainMenu from "./MainMenu/MainMenu";
export TodoList from "./TodoList/TodoList";
Then in your other file:
import { Footer, Header, Hero, MainMenu, TodoList } from "path to common.js"

External react component cannot see React.Component

The external React component says Uncaught TypeError: Cannot read property 'Component' of undefined when I link as npm package.
I link a package in package.json as "react-mapbox": "https://github.com/varya/react-mapbox.git". Then I use it in code
import {render} from 'react-dom';
import MapBox from "react-mapbox";
render(
<div>
<h1>Hello, world!</h1>
<MapBox />
</div>
,
document.getElementById('example')
);
But nothing works, I get that error. The full repo is here https://github.com/varya/react-mapbox-test I made a small example to illustrate.
The react-mapbox package is my own, maybe I build it wrongly? This is its repo https://github.com/varya/react-mapbox
I built it with webpack, like that https://github.com/varya/react-mapbox/blob/master/webpack.config.js As I suppose, this build does not include react package assuming that this will be at the project which link it. But the component still do not see react object.
UPD
I added import React from 'react'; as #aulizko suggested, but this only provided React object onto a page. It still was not visible for the component.
To fix this I had to provide this changes https://github.com/varya/react-mapbox/commit/2687d66025aaa84553a79850aa8686e88f1f39d9
I required react in the code of the component as well.
And I have to build with Babel. For some reason the webpack build gives the same error even if react is required. I created a branch to illustrate this https://github.com/varya/react-mapbox/tree/webpack Now I'm happy with Babel, but with this branch you can see what's wrong with webpack if interested.
You're probably bundling your module as UMD which is causing the bundle to utilized a global React variable which doesn't exist in the consumer app. You need to export the bundle as a CommonJS or AMD module using https://webpack.github.io/docs/configuration.html#output-librarytarget. Simple add libraryTarget: 'commonjs2 or libraryTarget: 'amd' to the output key in the webpack config and make sure you are importing react in your component.
I added import React from 'react'; as #aulizko suggested, but this only provided React object onto a page. It still was not visible for the component.
To fix this I had to provide this changes https://github.com/varya/react-mapbox/commit/2687d66025aaa84553a79850aa8686e88f1f39d9
I required react in the code of the component as well.
And I have to build with Babel. For some reason the webpack build gives the same error even if react is required. I created a branch to illustrate this https://github.com/varya/react-mapbox/tree/webpack Now I'm happy with Babel, but with this branch you can see what's wrong with webpack if interested.
The thing is that the jsx-code that you see in your editor is not the code that will be executed by node or browser.
If you look into code that are generated by the babel, you'll see something like this:
(0, _reactDom.render)(React.createElement(
'div',
null,
React.createElement(
'h1',
null,
'Hello, world!'
),
React.createElement(_reactMapbox2['default'], null)
), document.getElementById('example'));
So as you can see it uses React constant under the hood.
You need to explicitely import React if you want to use jsx-code.
Add something like this in your code and it'll work:
import React from 'react'; // <!--- add this!!!
import {render} from 'react-dom';
import MapBox from "react-mapbox";
// the rest of your code goes here...
You have to import React's Component it this way:
import {Component} from 'react';
or even:
import React, { Component, PropTypes } from 'react';

Categories