ReactJS: Uncaught ReferenceError: require is not defined - javascript

I'm trying to use DRY in React JS. I'm trying to use the same HTML partial in different files
partial:
var AdminMenu = React.createClass({
getInitialState: function() {
return {};
},
render: function() {
return (
<h1>Menu</h1>
);
}
});
I'm requeiring it in another file:
require('./scripts/adminMenu.js');
ReactDOM.render(
<AdminMenu/>,
document.getElementById('content')
);
But I'm getting an error:
Uncaught ReferenceError: require is not defined
this scripts are included on html page like:
<script type="text/babel" src="scripts/admin.js"></script>
I'm using webpack

If you are not using any module bundler like webpack or etc.
You should assign you components to some javascript global object, because objects from .jsx are not put in global scope
So here is the solution (used window object here)
Defined module:
window.AdminMenu = React.createClass({
getInitialState: function() {
return {};
},
render: function() {
return (
<h1>Menu</h1>
);
}
});
Where you use it:
ReactDOM.render(
<window.AdminMenu/>,
document.getElementById('content')
);

You have to use
const { Component } = React;
const { render } = ReactDOM;
in place of
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

Consider to use ES6 modules instead of require with React
export a module:
// src/hello.js
// export as default
export default const hello = ({name}) => (
<h1>Hello {name}</h1>
)
import a module:
// src/index.js
// import from relative directory (src)
import Hello from './hello'
const App = () => {
return (
<div>
<Hello name="Pavel" />
</div>
)
}

You should read more about modules for example here: https://www.sitepoint.com/understanding-es6-modules/
The main problems in your existing code are:
It looks, in spite of that you are using Webpack, you use it wrong way. In your final bundle (final JS file), it shouldn't contain any 'require' keywords. Did you use Babel with your webpack? Please, show us your WebPack config.
Your AdminMenu file looks not like module. Your adminMenu file should contain 'export' keyword, after that you will be able to 'require' or 'import' it from other files.
Also, you can write questions in comments with Russian if it is more convenient for you

Related

react code splitting: is the argument for the import() function not a string

This is very bizarre. During my attempt at code-splitting, I encountered this:
const g = "bi";
const importStr = `react-icons/${g.toLowerCase()}`;
console.log(importStr);
console.log(importStr === `react-icons/bi`);
import(importStr).then(module => {
console.log(module);
});
import(`react-icons/bi`).then(module => {
console.log(module);
});
In the above code, if I import "importStr", then the import throws an error:
Uncaught (in promise) Error: Cannot find module 'react-icons/bi'
But if I directly import "react-icons/bi", then there is no issue. As you see,
importStr === `react-icons/bi`
Why and how do I fix this? I can't actually directly use "react-icons/bi" because g is dynamic and could take other values.
I quote from the following comment
Webpack performs a static analyse at build time. It doesn't try to infer variables which that import(test) could be anything, hence the failure. It is also the case for import(path+"a.js").
Because of the tree shaking feature webpack tries to remove all unused code from the bundle. That also means something similar could work
import("react-icons/" + g)
Edit: as per your suggestion I updating this to
import("react-icons/" + g.toLowerCase()+ '/index.js')
An easy way to implement code splitting in React is with lazy loading, as seen here (this might be easier than importing a dynamic string):
const OtherComponent = React.lazy(() => import('./OtherComponent'));
This implementation will load the bundle with OtherComponent only when it is first rendered.
Example from reactjs.org:
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<section>
<OtherComponent />
<AnotherComponent />
</section>
</Suspense>
</div>
);
}
More info on React.lazy

import npm modules asynchronously in react.js

I am using parcel as a bundler in React.js project.
How to load npm modules asynchronously in react.js?
There is only one page that uses one specific npm module so I didn't need to load it at first loading.
By avoiding this, I would like to reduce the bundle size.
Could you let me the proper way to do this?
========================
And also, if I understood anything wrongly about the bundle size optimization and lazy loading, please let me know.
By using Dynamic Import you may import the package when you really need the package.
You can use a dynamic import inside an useEffect hook like:
const Page = (props) => {
useEffect(
() => {
const [momentjsPromise, cancel] = makeCancelable(import("moment"));
momentjsPromise.then((momentjs) => {
// handle states here
});
return () => {
cancel?.();
};
},
[
/* don't forget the dependencies */
],
);
};
You can use dynamic imports.
Let's say you want to import my-module:
const Component = () => {
useEffect(() => {
import('my-module').then(mod => {
// my-module is ready
console.log(mod);
});
}, []);
return <div>my app</div>
}
Another way is to code-splitt Component itself:
// ./Component.js
import myModule from 'my-module';
export default () => <div>my app</div>
// ./App.js
const OtherComponent = React.lazy(() => import('./Component'));
const App = () => (
<Suspense>
<OtherComponent />
<Suspense>
);
my-module will be splitted along with Component.
These two patterns should work with any bundler, but it will work client side only.

Import React on condition

I have a plain javascript website. I'm importing with webpack a react component and use it in the website.
The problem is the component only works if I import react(globally).
I only use this component once in a while so I only want to import react if needed.
I'm interested in such a thing:
if(some_condition){ import react and import my component}
How could I do this?
Thanks
You can do dynamic imports like this:
(async () => {
if (somethingIsTrue) {
import('/modules/my-module.js')
.then((module) => {
// Do something with the module.
});
}
})();
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports
You can use dynamic import.
if (condition) {
Promise.all([
import("react-dom"),
import("react"),
import("path/to/component"),
])
// if you use named export for component, just use name instead of `default`
.then(([{ render }, { createElement }, { default: Component }]) => {
// select element where you want to render
let root = document.getElementById("root");
// render your component
render(createElement(Component), root);
});
}

How can I dynamically export components in index.js?

I'm working on a project with nuxt.js and I want to implement the atomic design methodology
so I currently import the components like this
import ButtonStyled from '#/components/atoms/ButtonStyled.vue'
import TextLead from '#/components/atoms/TextLead.vue'
import InputSearch from '#/components/atoms/InputSearch.vue'
but I need to import like this
import {
ButtonStyled,
TextLead,
InputSearch
} from '#/components/atoms'
the closer I got was that,
/atoms/index.js
const req = require.context('./', true, /\.vue$/)
const modules = {}
req.keys().forEach(fileName => {
const componentName = fileName.replace(/^.+\/([^/]+)\.vue/, '$1')
modules[componentName] = req(fileName).default
})
export const { ButtonStyled, TextLead } = modules
but I'm still defining the export variable names statically, I need to define dynamics based on the components inside the folder
NOTE: I can not use
export default modules
if I use the above code snippet I will not be able to import the way I need it, which is:
import { ButtonStyled } from "#/components/atoms"
require.context is a quite obscure function in Webpack, you will have issues while running unit tests. But, to solve your problem; You will need to import the index.js file in the main.js of your project.
This is how I do it:
_globals.js
// Globally register all base components prefixed with _base for convenience, because they
// will be used very frequently. Components are registered using the
// PascalCased version of their file name.
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
const requireComponent = require.context('.', true, /_base-[\w-]+\.vue$/)
requireComponent.keys().forEach(fileName => {
const componentConfig = requireComponent(fileName)
const componentName = upperFirst(
camelCase(fileName.replace(/^\.\/_base/, '').replace(/\.\w+$/, ''))
)
Vue.component(componentName, componentConfig.default || componentConfig)
})
components/index.js
//...
import './_globals'
//...
main.js
//...
import './components' // This imports in the index.js
//...
This way your components loaded in with require.context() gets registered as a vue component and made globally available. I advice to only use global components with components that will be used a lot. Do not load a component globally if you intend to use it only one time.
You can find a working example here -> https://github.com/IlyasDeckers/vuetiful/tree/master/src
To get your unit tests working with jest, you will need to mock require.context(). This was a true pain, but can be achieved easily by using babel-plugin-transform-require-context
I try to use your way to do that, and known you have make a mistake at module.exports
module.exports can not use import , i think you may can do like this
at atoms/index.js
const req = require.context("./", true, /\.vue$/);
const atoms = {};
req.keys().forEach(fileName => {
const componentName = fileName.replace(/^.+\/([^/]+)\.vue/, "$1");
atoms[componentName] = req(fileName).default;
});
export default atoms;
at where to use
import k from "#/components/atoms/index.js";
export default {
components: {
test1: k.test1,
test2: k.test2
}
};
or index.js
import test1 from "./test1.vue";
import test2 from "./test2.vue";
export { test1, test2 };
and where to use like this
import {test1,test2} from "#/components/atoms/index.js";
export default {
components: {
test1,
test2
}
};
I created a library that does all this for me, maybe it helps other people.
named-exports

React.js: how to decouple jsx out of JavaScript

Is there any way to move the jsx from a component's render function to a separate file? If so, how do I reference the jsx in the render function?
You can use react-templates. It gives you exactly this separation between the markup and the component itself, and much more.
I found it very useful for my needs (a large scale web app).
One problem with moving templates into a separate file is that if you use handlers like:
var myTemplate = (
<form onSubmit={this.handleSubmit}></form>
);
and then in your component you use:
render: function() {
return myTemplate;
}
the generated template code will call this.handleSubmit(), so the "this" will be wrong and the handlers won't work. What you need to do is put them in a function, like this:
var myTemplate = function() {
return (
<form onSubmit={this.handleSubmit}></form>
);
};
then in your component's render function, you need to bind it to 'this' correctly, then call it, like this:
render: function() {
return myTemplate.bind(this)();
},
Now you can put that template definition anywhere, in a separate file or however you want to structure and reference your own code. (power to you! Don't listen to these crazy prescriptive frameworks! :) )
Here is a pattern for separating the template jsx that uses CommonJS modules in NodeJS, Browserify or Webpack. In NodeJS, I found the node-jsx module helpful to avoid the need to compile the JSX.
// index.js
require('node-jsx').install({extension: '.jsx'});
var React = require('react'),
Component = require('./your-component');
// your-component.jsx
var YourComponent,
React = require('react'),
template = require('./templates/your-component.jsx');
module.exports = YourComponent = React.createClass({
render: function() {
return template.call(this);
}
});
// templates/your-component.jsx
/** #jsx React.DOM */
var React = require('react');
module.exports = function() {
return (
<div>
Your template content.
</div>
);
};
Update 2015-1-30: incorporated suggestion in Damon Smith's answer to set this in the template function to the React component.
Update 12/2016: the current best practice is to use the .js extension and use a build tool like Babel to output the final javascript from your source. Take a look at create-react-app if you're just getting started. Also, the latest React best practices do recommend a separation between components that manage state (typically called "container components") and components that are presentational. These presentational components can now be written as functions, so they are not far off from the template function used in the previous example. Here is how I would recommend decoupling most of the presentational JSX code now. These examples still use the ES5 React.createClass() syntax.
// index.js
var React = require('react'),
ReactDOM = require('react-dom'),
YourComponent = require('./your-component');
ReactDOM.render(
React.createElement(YourComponent, {}, null),
document.getElementById('root')
);
// your-component.js
var React = require('react'),
YourComponentTemplate = require('./templates/your-component');
var YourComponentContainer = React.createClass({
getInitialState: function() {
return {
color: 'green'
};
},
toggleColor: function() {
this.setState({
color: this.state.color === 'green' ? 'blue' : 'green'
});
},
render: function() {
var componentProps = {
color: this.state.color,
onClick: this.toggleColor
};
return <YourComponentTemplate {...componentProps} />;
}
});
module.exports = YourComponentContainer;
// templates/your-component.js
var React = require('react');
module.exports = function YourComponentTemplate(props) {
return (
<div style={{color: props.color}} onClick={props.onClick}>
Your template content.
</div>
);
};
I just separated JSX into anonymous function files
template.js
export default (component) => {
return <h1>Hello {component.props.name}</h1>
}
my-component.js
import React, {Component} from 'react';
import template from './template';
export default MyComponent extends Component {
render() {
return template(this);
}
}
In template you can access props or state or functions using component variable.
If you don't use any module system, i.e. rely on script tags only, simple expose your JSX component in a global variable and use it when you need :
// component.js
var Component = React.createClass({ /* your component */ });
// main.js
React.renderComponent(Component({}), domNode);
Note : the script tag for component.js must appear before the script tag for main.js.
If you use a Commonjs-like module system like Browserify, simply export your component definition and require it when you need it.
// component.js
var React = require("react");
module.exports = React.createClass({ /* your component */ });
// main.js
var Component = require("component.js");
React.renderComponent(Component({}), domNode);

Categories