I am learning react and I am using the es6 class syntax (class ... instead of function.prototype). For the most part, all of my front end code can go into a single file per page so I was not intending to use a js bundler to separate all of my component classes into different files.
The problem is that I do have a couple of components that I would like to reuse between a few pages. I assumed that if I put those in a separate file and simply included both the main script and the component script in the html that the main script could reference the classes in the component script via global scope but that doesn't seem to be the case based on this error.
You can see the code below but I'm wondering if there is some way to reference classes in other files without bundling. I know you can do it with the older prototype style classes.
At the end of the html body in this order:
<script src="players/player_search.js" type="text/babel"></script>
<script src="players/players.js" type="text/babel"></script>
In player_search.js:
class PlayerSearch extends React.Component{...}
In players.js:
class LeaderboardPage extends React.Component{
render(){
return (
<div>
<PlayerSearch/>
It is considered bad practice as you are polluting the global scope.
If you really have to, you could always put them under window scope.
class PlayerSearch {}
window.PlayerSearch = PlayerSearch;
Inside your html you need to make a container to hold your react components.
<div id="root"></div>
Then you would usually have an index page to initialize react-dom and render your component.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App'; // or whatever you want
ReactDOM.render( <App / > , document.getElementById('root'));
I would recommend using create-react-app if possible
Related
I am very new to Vue and I have read an article or two about it (probably vaguely).
Also, Since I have some understanding of react, I tend to assume certain things to work the same way (but probably they do not)
Anyway, I just started with Quasar and was going through the Quasar boilerplate code
In the myLayout.vue file, I see being used inside my template
<template>
<q-layout view="lHh Lpr lFf">
<q-layout-header>
<q-toolbar
color="negative"
>
<q-btn
flat
dense
round
#click="leftDrawerOpen = !leftDrawerOpen"
aria-label="Menu"
>
<q-icon name="menu" />
</q-btn>
based on my vaguely understanding, I thought for every component we are using to whom we need to pass props we need to import it as well but unfortunately I can't see it in my import-script area
<script>
import { openURL } from 'quasar'
export default {
name: 'MyLayout',
data () {
return {
leftDrawerOpen: this.$q.platform.is.desktop
}
},
methods: {
openURL
}
}
</script>
I would've thought the script to be something like
<script>
import { openURL } from 'quasar'
import {q-icon} from "quasar"
or at least something like that but here we only have
import { openURL } from 'quasar'
Also, Even if we remove the above snippet, our boilerplate app looks to be working fine so here are my two questions
Question 1: What is the use of import { openURL } from 'quasar' (like what it does)
Question 2: How can template contain <quasar-icon> or <quasar-whatever> without even importing it in script tag?
How can template contain <quasar-icon> or <quasar-whatever> without even importing it in script tag?
There are two ways to import components. The first way (which I recommend, and being most similar to React) is to import the component and add it to the components option inside the component that you want to use it within.
App.vue
<div>
<my-component/>
</div>
import MyComponent from 'my-component'
export default {
components: {
MyComponent
}
}
The second way is to import it globally for use within any Vue component in your app. You need only do this once in the entry script of your app. This is what Quasar is doing.
main.js
import Vue from 'vue'
import MyComponent from 'my-component'
Vue.component('my-component', MyComponent)
What is the use of import { openURL } from 'quasar' (like what it does)
I'm not familiar with Quasar, so I can't give you a specific answer here (I don't know what openURL does). You should check the Quasar docs.
openURL is being used as a method here. Perhaps it is being called from somewhere in the template (which you have excluded from the question).
A1) Import statement is 1 way (es6) way to split your code into different files and then import functions/objects/vars from other files or npm modules see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
A2) Vue allows 2 mechanisms to register components. Global and local. Globally registered components does not have to be imported and registered in every component before use (in template or render fn). See URL from comment above https://v2.vuejs.org/v2/guide/components-registration.html#Global-Registration
I want to know that, how to access selectColumns menthod inside react-handsontable. I already tried to assign refs to hot table component <HotTable refs="hot"/> but still i cant access selectColumns method.
Thanks for reading this question.
#Sagar Any other approaches? It's not so convenient if we include HotTable in other components and can't render it in such way.
If we speak about this rows from example
const exampleComponent = ReactDOM.render(
<ExampleComponent />, document.getElementById('example')
);
window.hotInstance = exampleComponent.refs.hot.hotInstance;
it's okay, when we render it as a separate component. But if I import it in App component and then render App component via ReactDom.render, I have no refs, just empty object
What is the major benefit of writing
import React, { Component } from 'react';
class Link extends Component {
...
}
instead of
import React from 'react';
class Link extends React.Component {
...
}
when it comes to react 15.4.x??
In my perspective and in my case (correct me if I am wrong) it does not matter at all since:
I am using a webpack2 for making my bundles;
I use code splitting to split my app code from vendor code;
I use webpack.optimize.CommonsChunkPlugin plugin with minChunks: Infinity setting to make sure that all vendor code is included only once.
From understanding how ES6 imports work I understand that by using named import of {Component} I state that I want to use only Component component in my code, which looks.. cleaner.
But since whole React package is still used in the app, I can create my classes with extension from React.Component instead of just Component and in result webpack will still produce the same amount of code and my bundle size will be the same in both cases.
Am I correct?
There is no difference, React.Component is the same object as Component, the second way is more eloquent in my opinion, because it really explains that you are using the Component object from the React library.
The first one seems to refer a member,
but, it comes from the pre modules era of javascript, where everything had to be attached to the exported global namespace (just to avoid global namespace pollution).
something that could be under the hood:
// this should be assumed as an example only.
class React { ... }
class Component { ... }
React.Component = Component;
// ES6
export {Component}
export default React;
// ES5
window.React = React;
Note: as someone said, you also need to import React because JSX needs to have it on scope, but, if you want to avoid it, you can expose React globally (window.React = React)
This import statement:
import React, { Component } from 'react';
is really doing two things. It imports the default export, under the name React (which is just a convention, you could call it what you want). It also imports a named export, Component.
The reason that the default React is imported is actually to make JSX work. When your JSX code is transpiled, then it substitutes <div> for React.DOM.div(), so React must exist otherwise things break!
Importing both things separately means that your JSX works but you get to write Component instead of React.Component in your code.
When you do import anything from "react", then the whole file is going to get included either way - any attempt to reduce the bundle size (e.g. Dead Code Elimination, Tree Shaking) is an additional, separate step, which doesn't depend on your import statements but the parts of the code that you use.
In the case of this library, the sane thing happens: the child Component of the default export refers to the same thing as the named export Component.
However, bear in mind that this isn't guaranteed to be the case! If the React library code contained the following:
export default {
Component: "foo"
};
export const Component = "bar";
Then React.Component === "foo" and Component === "bar".
Let's say I have a normal react application using redux and some ajax calls.
If I want to pass it to someone I will give them the bundled js file I created with webpack and ask them to include it in their HTML + render a div with an id of "myApp" for example:
<div id="myApp"></div>
Ok, what if their website is also created with react, and they want to include my bundled js file inside one of their components, and of course render the relevant div?
I tried to use import or require to simulate this:
require('./path/to/myBundle.js');
import './path/to/myBundle.js';
Example:
//...
import './path/to/myBundle.js'; // the file that will render myApp to the relevant div
// ....
export function SomeApp(args){
return(
<div>
<div id="myApp"></div>
<SomeComponent />
</div>
);
};`
This does not work as I get some errors about:
Uncaught Error: Minified React error #37; visit
http://facebook.github.io/react/docs/error-decoder.html?invariant=37
for the full message or use the non-minified dev environment for full
errors and additional helpful warnings.
And when I visit this site I see:
_registerComponent(...): Target container is not a DOM element.
However, if they'll use this file (myBundle.js) outside their components (top level index.html for example) it will work just fine of course.
EDIT:
I forgot to mention that I think I know what the problem is, the application doesn't have the HTML ready with this div yet. but I don't know a good and native way to wait for it to exist.
EDIT #2 following #Frxstrem 's answer:
I'm trying to follow this answer but I think I'm doing it wrong.
I have 2 copies of corry house slingshot demo app as app1 and app2.
changed the 'output' on webpack.config.prod.js of app1 to:
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
filename: 'app1Bundle.js',
library: "App1",
libraryTarget: "umd"
},
I'm trying to render app1 inside the homepage component of app2.
so i copied the "published" files from app1 to the root of app2 and called the folder app1, then added an import call:
import {app1} from '../../app1/app1Bundle';
and a matching tag inside the return function:
const HomePage = () => {
return (
<div>
<app1 />
<h1>App 2</h1>
</div>
);
};
I get the same error as I posted above.
I also tried different combinations:
import app1 from '../../app1/app1Bundle'; // without curly braces
or even just getting the script as a normal js script
import '../../app1/app1Bundle';
or
require('../../app1/app1Bundle');
and then tried to render a normal div tag with an id of "app1"
const HomePage = () => {
return (
<div>
<div id="app1"></div>
<h1>App 2</h1>
</div>
);
};
nothing seems to work as I still get the same error.
I think the problem is the timing of the script load and the rendering of the elements. I think the div does not exist yet when the bundled script is searching for it.
By default, Webpack will expose the entry module as a variable, which is useful when you include scripts with a <script> tag. (Because of this, if you require it you would likely just get {}.) However, if you want to load your bundle from other modules, you'll need to tell Webpack to expose it as an exported module instead.
The easiest way to do this is to set
{
...
"libraryTarget": "umd"
}
in your Webpack configuration. With that, Webpack knows that it should expose your entry module as a module that can be required in Webpack, but can also be loaded with a <script> tag as necessary.
Webpack libraryTarget documentation
The main problem i faced was to include the bundled js file of app1 after the DOM contains the target div it needs.
What i ended up doing was, creating a component in app2 project that will require() the bundled js file on componentDidMount() and will render and return the target div with a relevant id.
The reason i created a component is purely for re-usability purpose, instead of requiring this script with componentDidMount() on every component that needs it.
So, this is the component:
import React from 'react';
class AppOne extends React.Component {
componentDidMount() {
require('../app1/app1Bundle.js');
}
render() {
return (
<div id="app1"></div>
);
}
}
export default AppOne;
And this is how i use it in other component:
import React from 'react';
import AppOne from './AppOne';
const HomePage = () => {
return (
<div>
<h1>App 2 - wrapper for app1</h1>
<hr />
<AppOne />
<hr />
<h1>This is App2 as well </h1>
</div>
);
};
export default HomePage;
It's working fine. my only concern is that i may face some conflicts with react because i'm using 2 react apps though for ow i don't see any errors.
I guess that's an issue for a different question.
EDIT:
If someone will use this approach you should note that this will work only for the first load. because after the component will re-render itself the bundled script will not run again.
Complete newbie to React and trying to find out how to load the HTML for components rather than inserting it directly in the render method. For example
import React, {Component} from 'react';
export default class Login extends Component {
render() {
return (
<!-- how can I provide a link to the HTML template for here? -->
);
}
}
React does not have HTML. The JSX that you write in the render method is actually compiled into JavaScript. At the core, React components are all JavaScript. The styles are also inline. Componentisation is neat in React because HTML, CSS, JavaScript (interactions) are all in one place, as JavaScript.
To insert raw HTML, React has an attribute dangerouslySetInnerHTML.
<div dangerouslySetInnerHTML={createMarkup()} />
If you want some type of organization, you can use variables to set the html and then assign that to the render functionalty, but React does not use html templates
var hello = React.createClass({
render: yourVariable
});
I think you might be confused about how JSX works.Just in case, I want to clarify that JSX is what they call "syntactic sugar", that turns React methods such as React.createElement into that XML like syntax. For instance:
var Nav;
// Input (JSX):
var app = <Nav color="blue" />;
// Output (JS):
var app = React.createElement(Nav, {color:"blue"});
(from the React docs)
So, to the best of my knowledge, the JSX syntax actually belongs in the render method. If what you are really looking for is the best way to separate and reuse purely presentational code, you should read on separating your app into Container and Presentational components
https://medium.com/#learnreact/container-components-c0e67432e005#.dzjqc8yrn
https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.mn9nf6lz6
Stateless/Presentational/Dumb Components are just functions that return JSX. So you could have your Template component:
import React from 'react';
//you need to import React to use JSX, as it will be expanded into React.createElement calls...
function Template(props){
return (
//...your template here...
);
}
And then your class
import React, {Component} from 'react';
export default class Login extends Component {
render() {
return (<Template {...props}/>);
}
}
}
Makes sense?